├── Demo ├── Shared │ ├── Assets.xcassets │ │ ├── Contents.json │ │ └── AccentColor.colorset │ │ │ └── Contents.json │ ├── SporthAudioKitDemoApp.swift │ ├── Reusable Components │ │ └── Global.swift │ ├── ContentView.swift │ └── Operations │ │ ├── StereoOperation.swift │ │ ├── DroneOperation.swift │ │ ├── CrossingSignal.swift │ │ ├── PhasorOperation.swift │ │ ├── VocalTractOperation.swift │ │ └── LFOOperation.swift ├── SporthAudioKitDemo.xcodeproj │ └── project.xcworkspace │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── macOS │ └── macOS.entitlements ├── .gitignore ├── .github ├── CODEOWNERS └── workflows │ └── tests.yml ├── Sources ├── CSporthAudioKit │ └── include │ │ └── CSporthAudioKit.h ├── SporthAudioKit │ ├── Math │ │ ├── CP+trackedAmplitude.swift │ │ ├── Operation+Save.swift │ │ └── Operation+Segments.swift │ ├── Music │ │ ├── Operation+PitchShift.swift │ │ ├── Operation+Portamento.swift │ │ ├── Operation+TriggeredWithEnvelope.swift │ │ └── Operation+PeriodicTriggers.swift │ ├── Numeric.swift │ ├── Generators │ │ ├── Operation+GatedADSREnvelope.swift │ │ ├── Operation+Noise.swift │ │ └── Operation+PhysicalModels.swift │ ├── Parameter.swift │ └── MixingOperations.swift └── Sporth │ ├── ugens │ ├── mark.c │ ├── in.c │ ├── ref.c │ ├── say.c │ ├── eval.c │ ├── srand.c │ ├── writecode.c │ ├── brown.c │ ├── tick.c │ ├── changed.c │ ├── scrambler.c │ ├── zeros.c │ ├── metro.c │ ├── gen_sine.c │ ├── tog.c │ ├── gen_rand.c │ ├── dcblock.c │ ├── gen_composite.c │ ├── load.c │ ├── noise.c │ ├── gen_vals.c │ ├── rms.c │ ├── tin.c │ ├── jcrev.c │ ├── timer.c │ ├── dmetro.c │ ├── rand.c │ ├── pinknoise.c │ ├── bal.c │ ├── gen_sinesum.c │ ├── tone.c │ ├── clip.c │ ├── switch.c │ ├── atone.c │ ├── sdelay.c │ ├── gen_line.c │ ├── buthp.c │ ├── butlp.c │ ├── delay.c │ ├── hilbert.c │ ├── reverse.c │ ├── phasor.c │ ├── tgate.c │ ├── blsaw.c │ ├── pdhalf.c │ ├── samphold.c │ ├── butbp.c │ ├── butbr.c │ ├── maygate.c │ ├── dust.c │ ├── maytrig.c │ ├── bltriangle.c │ ├── line.c │ ├── mode.c │ ├── pan.c │ ├── expon.c │ ├── scale.c │ ├── count.c │ ├── trand.c │ ├── comb.c │ ├── tenv2.c │ ├── tdiv.c │ ├── lpf18.c │ ├── reson.c │ ├── clock.c │ ├── eqfil.c │ ├── rspline.c │ ├── diode.c │ ├── randi.c │ ├── waveset.c │ ├── biscale.c │ ├── randh.c │ ├── thresh.c │ ├── crossfade.c │ ├── allpass.c │ ├── gen_padsynth.c │ ├── jitter.c │ ├── tenv.c │ ├── streson.c │ ├── bitcrush.c │ ├── blsquare.c │ ├── moogladder.c │ └── tphasor.c │ ├── sporth.c │ └── hash.c ├── SporthAudioKit.playground ├── contents.xcplayground └── Pages │ ├── Noise Operations.xcplaygroundpage │ └── Contents.swift │ ├── Sawtooth Wave Oscillator Operation.xcplaygroundpage │ └── Contents.swift │ ├── Phasor Operation.xcplaygroundpage │ └── Contents.swift │ ├── Pedestrians.xcplaygroundpage │ └── Contents.swift │ ├── Vocal Tract Operation.xcplaygroundpage │ └── Contents.swift │ ├── LFO.xcplaygroundpage │ └── Contents.swift │ ├── Plucked String Operation.xcplaygroundpage │ └── Contents.swift │ └── FM Oscillator Operation.xcplaygroundpage │ └── Contents.swift ├── Tests ├── SporthAudioKitTests │ ├── Effect Tests │ │ ├── reverberateWithCostelloOperationTests.swift │ │ ├── variableDelayOperationTests.swift │ │ ├── threePoleLowPassFilterOperationTests.swift │ │ ├── autoWahOperationTests.swift │ │ └── delayOperationTests.swift │ └── Generator Tests │ │ ├── pinkNoiseOperationTests.swift │ │ ├── whiteNoiseOperationTests.swift │ │ ├── triangleWaveOperationTests.swift │ │ ├── triangleOperationTests.swift │ │ ├── fmOscillatorOperationTests.swift │ │ └── vocalTractOperationTests.swift └── CSporthAudioKitTests │ └── SoundpipePerfTests.mm ├── Package.swift ├── LICENSE └── README.md /Demo/Shared/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | ### SwiftPackageManager ### 4 | Packages 5 | .build/ 6 | xcuserdata 7 | DerivedData/ 8 | *.xcworkspacedata 9 | 10 | Package.resolved -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # AudioKit Code Owners File 2 | # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners 3 | 4 | # Primary Owners 5 | * @aure @wtholliday -------------------------------------------------------------------------------- /Demo/Shared/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/CSporthAudioKit/include/CSporthAudioKit.h: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #import "SoundpipeDSPBase.h" 6 | 7 | CF_EXTERN_C_BEGIN 8 | void akOperationSetSporth(DSPRef dspRef, const char *sporth); 9 | CF_EXTERN_C_END -------------------------------------------------------------------------------- /Demo/SporthAudioKitDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demo/Shared/SporthAudioKitDemoApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SporthAudioKitDemoApp.swift 3 | // Shared 4 | // 5 | // Created by Aurelius Prochazka on 9/6/22. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct SporthAudioKitDemoApp: App { 12 | var body: some Scene { 13 | WindowGroup { 14 | ContentView() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Demo/macOS/macOS.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Sources/SporthAudioKit/Math/CP+trackedAmplitude.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | public extension ComputedParameter { 4 | /// Tracked amplitude 5 | /// 6 | /// - parameter input: Input audio signal 7 | /// 8 | func trackedAmplitude(_: OperationParameter = 0) -> Operation { 9 | return Operation(module: "rms", inputs: toMono()) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Demo/Shared/Reusable Components/Global.swift: -------------------------------------------------------------------------------- 1 | import AudioKit 2 | import AudioKitUI 3 | import AVFoundation 4 | import SwiftUI 5 | 6 | // Helper functions 7 | class Global { 8 | static var sourceBuffer: AVAudioPCMBuffer { 9 | let url = Bundle.main.resourceURL?.appendingPathComponent("Samples/beat.aiff") 10 | let file = try! AVAudioFile(forReading: url!) 11 | return try! AVAudioPCMBuffer(file: file)! 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/SporthAudioKit/Music/Operation+PitchShift.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | public extension ComputedParameter { 4 | /// Alter the average frequency of signal 5 | /// 6 | /// - Parameter semitones: Amount of shift 7 | /// 8 | func pitchShift(semitones: OperationParameter = 0) -> Operation { 9 | return Operation(module: "1000 100 pshift", inputs: toMono(), semitones) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/SporthAudioKit/Math/Operation+Save.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | public extension Operation { 4 | /// Save a value into the parameters array for using outside of the operation 5 | /// 6 | /// - parameter parameterIndex: Location in the parameters array to save this value 7 | /// 8 | func save(parameterIndex: Int) -> Operation { 9 | return Operation(module: "dup \(parameterIndex) pset", inputs: toMono()) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/SporthAudioKit/Numeric.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | // MARK: Numeric Protocol 4 | 5 | /// Very simple protocol for anything with an intrinsic floating point value. 6 | /// Allows constants to be passed into an AudioKit operation as well as other operations. 7 | public protocol Numeric: OperationParameter { 8 | /// Raw value of the numeric parameter 9 | func value() -> Double 10 | } 11 | 12 | /// Numeric extension for doubles 13 | extension Double: Numeric { 14 | /// Get basic value as a double 15 | public func value() -> Double { 16 | return Double(self) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SporthAudioKit.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Tests/SporthAudioKitTests/Effect Tests/reverberateWithCostelloOperationTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | import AudioKit 4 | import SoundpipeAudioKit 5 | import SporthAudioKit 6 | import XCTest 7 | 8 | class ReverberateWithCostelloTests: XCTestCase { 9 | func testDefault() { 10 | let engine = AudioEngine() 11 | let input = Oscillator(waveform: Table(.triangle)) 12 | engine.output = OperationEffect(input) { $0.reverberateWithCostello() } 13 | input.start() 14 | let audio = engine.startTest(totalDuration: 1.0) 15 | audio.append(engine.render(duration: 1.0)) 16 | testMD5(audio) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SporthAudioKit.playground/Pages/Noise Operations.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: ## Noise Operations 2 | //: 3 | import AudioKit 4 | import PlaygroundSupport 5 | import SporthAudioKit 6 | 7 | let generator = OperationGenerator { _ in 8 | let white = Operation.whiteNoise() 9 | let pink = Operation.pinkNoise() 10 | 11 | let lfo = Operation.sineWave(frequency: 0.3) 12 | let balance = lfo.scale(minimum: 0, maximum: 1) 13 | let noise = mixer(white, pink, balance: balance) 14 | return noise.pan(lfo) 15 | } 16 | 17 | let engine = AudioEngine() 18 | engine.output = generator 19 | 20 | try! engine.start() 21 | generator.start() 22 | 23 | PlaygroundPage.current.needsIndefiniteExecution = true 24 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/mark.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "plumber.h" 6 | 7 | int sporth_markleft(sporth_stack *stack, void *ud) 8 | { 9 | plumber_data *pd = ud; 10 | switch(pd->mode){ 11 | case PLUMBER_CREATE: 12 | plumber_add_ugen(pd, SPORTH_MARKLEFT, NULL); 13 | default: 14 | break; 15 | } 16 | return PLUMBER_OK; 17 | } 18 | int sporth_markright(sporth_stack *stack, void *ud) 19 | { 20 | plumber_data *pd = ud; 21 | switch(pd->mode){ 22 | case PLUMBER_CREATE: 23 | plumber_add_ugen(pd, SPORTH_MARKRIGHT, NULL); 24 | default: 25 | break; 26 | } 27 | return PLUMBER_OK; 28 | } 29 | -------------------------------------------------------------------------------- /Sources/SporthAudioKit/Music/Operation+Portamento.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | public extension Operation { 4 | /// Portamento-style control signal smoothing 5 | /// Useful for smoothing out low-resolution signals and applying glissando to 6 | /// filters. 7 | /// 8 | /// - Parameters: 9 | /// - input: Input audio signal 10 | /// - halfDuration: Duration which the curve will traverse half the distance towards the new value, 11 | /// then half as much again, etc., theoretically never reaching its asymptote. (Default: 0.02) 12 | /// 13 | func portamento(halfDuration: OperationParameter = 0.02) -> Operation { 14 | return Operation(module: "port", inputs: self, halfDuration) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SporthAudioKit.playground/Pages/Sawtooth Wave Oscillator Operation.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: ## Sawtooth Wave Oscillator Operation 2 | //: Maybe the most annoying sound ever. Sorry. 3 | //: 4 | import AudioKit 5 | import PlaygroundSupport 6 | import SporthAudioKit 7 | 8 | //: Set up the operations that will be used to make a generator node 9 | 10 | let generator = OperationGenerator { _ in 11 | let freq = Operation.jitter(amplitude: 200, minimumFrequency: 1, maximumFrequency: 10) + 200 12 | let amp = Operation.randomVertexPulse(minimum: 0, maximum: 0.3, updateFrequency: 1) 13 | return Operation.sawtoothWave(frequency: freq, amplitude: amp) 14 | } 15 | 16 | let engine = AudioEngine() 17 | engine.output = generator 18 | 19 | try! engine.start() 20 | generator.start() 21 | 22 | PlaygroundPage.current.needsIndefiniteExecution = true 23 | -------------------------------------------------------------------------------- /Tests/SporthAudioKitTests/Generator Tests/pinkNoiseOperationTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | import AudioKit 4 | import SporthAudioKit 5 | import XCTest 6 | 7 | class PinkNoiseOperationTests: XCTestCase { 8 | func testParameterSweep() { 9 | let engine = AudioEngine() 10 | let noise = OperationGenerator { 11 | let line = Operation.lineSegment( 12 | trigger: Operation.metronome(), 13 | start: 0, 14 | end: 1, 15 | duration: 1.0 16 | ) 17 | return Operation.pinkNoise(amplitude: line) 18 | } 19 | engine.output = noise 20 | noise.start() 21 | let audio = engine.startTest(totalDuration: 1.0) 22 | audio.append(engine.render(duration: 1.0)) 23 | testMD5(audio) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/SporthAudioKit/Music/Operation+TriggeredWithEnvelope.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | public extension Operation { 4 | /// Trigger based linear AHD envelope generator 5 | /// 6 | /// - Parameters: 7 | /// - trigger: A triggering operation such as a metronome 8 | /// - attack: Attack duration, in seconds. (Default: 0.1) 9 | /// - hold: Hold duration, in seconds. (Default: 0.3) 10 | /// - release: Release duration, in seconds. (Default: 0.2) 11 | /// 12 | func triggeredWithEnvelope( 13 | trigger: OperationParameter, 14 | attack: OperationParameter = 0.1, 15 | hold: OperationParameter = 0.3, 16 | release: OperationParameter = 0.2 17 | ) -> Operation { 18 | return Operation(module: "tenv *", inputs: self, trigger, attack, hold, release) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Tests/SporthAudioKitTests/Generator Tests/whiteNoiseOperationTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | import AudioKit 4 | import SporthAudioKit 5 | import XCTest 6 | 7 | class WhiteNoiseOperationTests: XCTestCase { 8 | func testParameterSweep() { 9 | let engine = AudioEngine() 10 | let noise = OperationGenerator { 11 | let line = Operation.lineSegment( 12 | trigger: Operation.metronome(), 13 | start: 0, 14 | end: 1, 15 | duration: 1.0 16 | ) 17 | return Operation.whiteNoise(amplitude: line) 18 | } 19 | engine.output = noise 20 | noise.start() 21 | let audio = engine.startTest(totalDuration: 1.0) 22 | audio.append(engine.render(duration: 1.0)) 23 | testMD5(audio) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/SporthAudioKit/Generators/Operation+GatedADSREnvelope.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | public extension Operation { 4 | /// Gate based linear AHD envelope generator 5 | /// 6 | /// - Parameters: 7 | /// - gate: 1 for on and 0 for off 8 | /// - attack: Attack duration, in seconds. (Default: 0.1) 9 | /// - hold: Hold duration, in seconds. (Default: 0.3) 10 | /// - release: Release duration, in seconds. (Default: 0.2) 11 | /// 12 | func gatedADSREnvelope( 13 | gate: OperationParameter, 14 | attack: OperationParameter = 0.1, 15 | decay: OperationParameter = 0.0, 16 | sustain: OperationParameter = 1, 17 | release: OperationParameter = 0.2 18 | ) -> Operation { 19 | return Operation(module: "adsr *", inputs: toMono(), gate, attack, decay, sustain, release) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Tests/SporthAudioKitTests/Generator Tests/triangleWaveOperationTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | import AudioKit 4 | import SporthAudioKit 5 | import XCTest 6 | 7 | class TriangleWaveTests: XCTestCase { 8 | func testParameterSweep() { 9 | let engine = AudioEngine() 10 | let triangle = OperationGenerator { 11 | let ramp = Operation.lineSegment( 12 | trigger: Operation.metronome(), 13 | start: 1, 14 | end: 0, 15 | duration: 1.0 16 | ) 17 | return Operation.triangleWave(frequency: ramp * 2000, amplitude: ramp) 18 | } 19 | engine.output = triangle 20 | triangle.start() 21 | let audio = engine.startTest(totalDuration: 1.0) 22 | audio.append(engine.render(duration: 1.0)) 23 | testMD5(audio) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/SporthAudioKitTests/Generator Tests/triangleOperationTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | import AudioKit 4 | import SporthAudioKit 5 | import XCTest 6 | 7 | class TriangleTests: XCTestCase { 8 | func testParameterSweep() { 9 | let engine = AudioEngine() 10 | let triangle = OperationGenerator { 11 | let ramp = Operation.lineSegment( 12 | trigger: Operation.metronome(), 13 | start: 1.0, 14 | end: 0.0, 15 | duration: 1.0 16 | ) 17 | return Operation.triangle(frequency: ramp * 2000, amplitude: ramp, phase: ramp) 18 | } 19 | engine.output = triangle 20 | triangle.play() 21 | let audio = engine.startTest(totalDuration: 1.0) 22 | audio.append(engine.render(duration: 1.0)) 23 | testMD5(audio) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/SporthAudioKit/Music/Operation+PeriodicTriggers.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | public extension Operation { 4 | /// Metro produces a series of 1-sample ticks at a regular rate. Typically, this 5 | /// is used alongside trigger-driven modules. 6 | /// 7 | /// - parameter frequency: The frequency to repeat. (Default: 2.0) 8 | /// 9 | static func metronome(frequency: OperationParameter = 2.0) -> Operation { 10 | return Operation(module: "metro", inputs: frequency) 11 | } 12 | 13 | /// Produce a set of triggers spaced apart by time. 14 | /// 15 | /// - parameter period: Time between triggers (in seconds). Updates at the start of each trigger. (Default: 1.0) 16 | /// 17 | static func periodicTrigger(period: OperationParameter = 1.0) -> Operation { 18 | return Operation(module: "dmetro", inputs: period) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Tests/SporthAudioKitTests/Effect Tests/variableDelayOperationTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | import AudioKit 4 | import SoundpipeAudioKit 5 | import SporthAudioKit 6 | import XCTest 7 | 8 | class VariableDelayOperationTests: XCTestCase { 9 | func testParameterSweep() { 10 | let engine = AudioEngine() 11 | let input = Oscillator(waveform: Table(.triangle)) 12 | engine.output = OperationEffect(input) { input in 13 | let ramp = Operation.lineSegment( 14 | trigger: Operation.metronome(), 15 | start: 1, 16 | end: 0, 17 | duration: 1.0 18 | ) 19 | return input.variableDelay(time: 0.1 * ramp, feedback: 0.9 * ramp) 20 | } 21 | input.start() 22 | let audio = engine.startTest(totalDuration: 1.0) 23 | audio.append(engine.render(duration: 1.0)) 24 | testMD5(audio) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Sporth/sporth.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "plumber.h" 4 | 5 | typedef struct { 6 | plumber_data pd; 7 | } UserData; 8 | 9 | static void process(sp_data *sp, void *udata){ 10 | UserData *ud = udata; 11 | plumber_data *pd = &ud->pd; 12 | SPFLOAT out = 0; 13 | int chan; 14 | 15 | if(pd->recompile) { 16 | plumber_recompile_string(&ud->pd, pd->str); 17 | pd->recompile = 0; 18 | } 19 | 20 | plumber_compute(pd, PLUMBER_COMPUTE); 21 | 22 | for (chan = 0; chan < pd->nchan; chan++) { 23 | out = sporth_stack_pop_float(&pd->sporth.stack); 24 | sp->out[chan] = out; 25 | } 26 | 27 | if(pd->showprog) { 28 | sp_progress_compute(sp, pd->prog, NULL, NULL); 29 | } 30 | } 31 | 32 | #if 0 33 | int main(int argc, char *argv[]) 34 | { 35 | UserData ud; 36 | plumber_init(&ud.pd); 37 | sporth_run(&ud.pd, argc, argv, &ud, process); 38 | return 0; 39 | } 40 | #endif 41 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.5 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "SporthAudioKit", 8 | platforms: [.macOS(.v12), .iOS(.v13), .tvOS(.v13)], 9 | products: [.library(name: "SporthAudioKit", targets: ["SporthAudioKit"])], 10 | dependencies: [.package(url: "https://github.com/AudioKit/SoundpipeAudioKit", from: "5.5.1")], 11 | targets: [ 12 | .target(name: "Sporth", dependencies: ["SoundpipeAudioKit"]), 13 | .target(name: "SporthAudioKit", dependencies: ["SoundpipeAudioKit", "CSporthAudioKit", "Sporth"]), 14 | .target(name: "CSporthAudioKit", dependencies: ["SoundpipeAudioKit", "Sporth"]), 15 | .testTarget(name: "SporthAudioKitTests", dependencies: ["SporthAudioKit"]), 16 | .testTarget(name: "CSporthAudioKitTests", dependencies: ["CSporthAudioKit"]), 17 | ], 18 | cxxLanguageStandard: .cxx14 19 | ) 20 | -------------------------------------------------------------------------------- /Tests/SporthAudioKitTests/Effect Tests/threePoleLowPassFilterOperationTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | import AudioKit 4 | import SoundpipeAudioKit 5 | import SporthAudioKit 6 | import XCTest 7 | 8 | class ThreePoleLowPassFilterOperationTests: XCTestCase { 9 | func testParameterSweep() { 10 | let engine = AudioEngine() 11 | let input = Oscillator(waveform: Table(.triangle)) 12 | engine.output = OperationEffect(input) { input in 13 | let ramp = Operation.lineSegment( 14 | trigger: Operation.metronome(), 15 | start: 1, 16 | end: 0, 17 | duration: 1.0 18 | ) 19 | return input.threePoleLowPassFilter(distortion: ramp, cutoffFrequency: ramp * 8000, resonance: ramp * 0.9) 20 | } 21 | input.start() 22 | let audio = engine.startTest(totalDuration: 1.0) 23 | audio.append(engine.render(duration: 1.0)) 24 | testMD5(audio) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SporthAudioKit.playground/Pages/Phasor Operation.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: ## Phasor Operation 2 | //: Using the phasor to sweep amplitude and frequencies 3 | //: 4 | import AudioKit 5 | import PlaygroundSupport 6 | import SporthAudioKit 7 | 8 | let interval: Double = 2 9 | let noteCount: Double = 24 10 | let startingNote: Double = 48 // C 11 | 12 | let generator = OperationGenerator { _ in 13 | 14 | let frequency = (floor(Operation.phasor(frequency: 0.5) * noteCount) * interval + startingNote) 15 | .midiNoteToFrequency() 16 | 17 | let amplitude = (Operation.phasor(frequency: 0.5) - 1).portamento() // prevents the click sound 18 | 19 | let oscillator = Operation.sineWave(frequency: frequency, amplitude: amplitude) 20 | let reverb = oscillator.reverberateWithChowning() 21 | return mixer(oscillator, reverb, balance: 0.6) 22 | } 23 | 24 | let engine = AudioEngine() 25 | engine.output = generator 26 | 27 | try! engine.start() 28 | generator.start() 29 | 30 | PlaygroundPage.current.needsIndefiniteExecution = true 31 | -------------------------------------------------------------------------------- /Tests/SporthAudioKitTests/Effect Tests/autoWahOperationTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | import AudioKit 4 | import SoundpipeAudioKit 5 | import SporthAudioKit 6 | import XCTest 7 | 8 | class AutoWahOperationTests: XCTestCase { 9 | func testAmplitude() { 10 | let engine = AudioEngine() 11 | let input = Oscillator(waveform: Table(.triangle)) 12 | engine.output = OperationEffect(input) { $0.autoWah(wah: 0.5, amplitude: 0.5) } 13 | input.start() 14 | let audio = engine.startTest(totalDuration: 1.0) 15 | audio.append(engine.render(duration: 1.0)) 16 | testMD5(audio) 17 | } 18 | 19 | func testWah() { 20 | let engine = AudioEngine() 21 | let input = Oscillator(waveform: Table(.triangle)) 22 | engine.output = OperationEffect(input) { $0.autoWah(wah: 0.5) } 23 | input.start() 24 | let audio = engine.startTest(totalDuration: 1.0) 25 | audio.append(engine.render(duration: 1.0)) 26 | testMD5(audio) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/in.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_in(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | 7 | SPFLOAT out; 8 | sp_in *data; 9 | switch(pd->mode){ 10 | case PLUMBER_CREATE: 11 | sp_in_create(&data); 12 | plumber_add_ugen(pd, SPORTH_IN, data); 13 | sporth_stack_push_float(stack, 0); 14 | break; 15 | case PLUMBER_INIT: 16 | data = pd->last->ud; 17 | sp_in_init(pd->sp, data); 18 | sporth_stack_push_float(stack, 0); 19 | break; 20 | case PLUMBER_COMPUTE: 21 | data = pd->last->ud; 22 | sp_in_compute(pd->sp, data, NULL, &out); 23 | sporth_stack_push_float(stack, out); 24 | break; 25 | case PLUMBER_DESTROY: 26 | data = pd->last->ud; 27 | sp_in_destroy(&data); 28 | break; 29 | default: 30 | printf("Error: Unknown mode!"); 31 | break; 32 | } 33 | return PLUMBER_OK; 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/ref.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | int sporth_ref(sporth_stack *stack, void *ud) 3 | { 4 | plumber_data *pd = ud; 5 | const char *str; 6 | switch(pd->mode) { 7 | case PLUMBER_CREATE: 8 | plumber_add_ugen(pd, SPORTH_REF, NULL); 9 | if(sporth_check_args(stack, "s") != SPORTH_OK) { 10 | stack->error++; 11 | plumber_print(pd, "ref: Invalid arguments."); 12 | return PLUMBER_NOTOK; 13 | } 14 | sporth_stack_pop_string(stack); 15 | break; 16 | case PLUMBER_INIT: 17 | str = sporth_stack_pop_string(stack); 18 | plumber_ftmap_delete(pd, 0); 19 | /* get reference of the *next* pipe in the plumbing */ 20 | plumber_ftmap_add_userdata(pd, str, pd->next->ud); 21 | plumber_ftmap_delete(pd, 1); 22 | break; 23 | case PLUMBER_COMPUTE: 24 | break; 25 | case PLUMBER_DESTROY: 26 | break; 27 | } 28 | return PLUMBER_OK; 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/say.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "plumber.h" 5 | 6 | int sporth_say(sporth_stack *stack, void *ud) 7 | { 8 | plumber_data *pd = ud; 9 | const char *str; 10 | switch(pd->mode) { 11 | case PLUMBER_CREATE: 12 | plumber_add_ugen(pd, SPORTH_SAY, NULL); 13 | if(sporth_check_args(stack, "s") != SPORTH_OK) { 14 | plumber_print(pd,"Say: not enough arguments.\n"); 15 | stack->error++; 16 | return PLUMBER_NOTOK; 17 | } 18 | str = sporth_stack_pop_string(stack); 19 | plumber_print(pd, "%s\n", str); 20 | break; 21 | case PLUMBER_INIT: 22 | str = sporth_stack_pop_string(stack); 23 | break; 24 | case PLUMBER_COMPUTE: 25 | break; 26 | case PLUMBER_DESTROY: 27 | break; 28 | default: 29 | plumber_print(pd, "print: Unknown mode!\n"); 30 | break; 31 | } 32 | return PLUMBER_OK; 33 | } 34 | -------------------------------------------------------------------------------- /SporthAudioKit.playground/Pages/Pedestrians.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: ## Pedestrians 2 | //: A British crossing signal implemented with AudioKit, an example from 3 | //: Andy Farnell's excellent book "Designing Sound" 4 | //: 5 | import AudioKit 6 | import PlaygroundSupport 7 | import SporthAudioKit 8 | 9 | let generator = OperationGenerator { 10 | // Generate a sine wave at the right frequency 11 | let crossingSignalTone = Operation.sineWave(frequency: 2500) 12 | 13 | // Periodically trigger an envelope around that signal 14 | let crossingSignalTrigger = Operation.periodicTrigger(period: 0.2) 15 | let crossingSignal = crossingSignalTone.triggeredWithEnvelope( 16 | trigger: crossingSignalTrigger, 17 | attack: 0.01, 18 | hold: 0.1, 19 | release: 0.01 20 | ) 21 | 22 | // scale the volume 23 | return crossingSignal * 0.2 24 | } 25 | 26 | let engine = AudioEngine() 27 | engine.output = generator 28 | 29 | try! engine.start() 30 | generator.start() 31 | 32 | PlaygroundPage.current.needsIndefiniteExecution = true 33 | -------------------------------------------------------------------------------- /Sources/SporthAudioKit/Generators/Operation+Noise.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | public extension Operation { 4 | /// Brownian noise generator 5 | /// 6 | /// - parameter amplitude: Overall level. (Default: 1.0, Minimum: 0, Maximum: 1.0) 7 | /// 8 | static func brownianNoise(amplitude: OperationParameter = 1.0) -> Operation { 9 | return Operation(module: "brown *", inputs: amplitude) 10 | } 11 | 12 | /// Faust-based pink noise generator 13 | /// 14 | /// - parameter amplitude: Overall level. (Default: 1.0, Minimum: 0, Maximum: 1.0) 15 | /// 16 | static func pinkNoise(amplitude: OperationParameter = 1.0) -> Operation { 17 | return Operation(module: "pinknoise", inputs: amplitude) 18 | } 19 | 20 | /// White noise generator 21 | /// 22 | /// - parameter amplitude: Overall level. (Default: 1.0, Minimum: 0.0, Maximum: 10.0) 23 | /// 24 | static func whiteNoise(amplitude: OperationParameter = 1.0) -> Operation { 25 | return Operation(module: "noise", inputs: amplitude) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 AudioKit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Tests/SporthAudioKitTests/Generator Tests/fmOscillatorOperationTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | import AudioKit 4 | import SporthAudioKit 5 | import XCTest 6 | 7 | class FMOscillatorOperationTests: XCTestCase { 8 | func testFMOscillatorOperation() { 9 | let engine = AudioEngine() 10 | let oscillator = OperationGenerator { 11 | let line = Operation.lineSegment( 12 | trigger: Operation.metronome(frequency: 0.1), 13 | start: 0.001, 14 | end: 5, 15 | duration: 1.0 16 | ) 17 | return Operation.fmOscillator( 18 | baseFrequency: line * 1000, 19 | carrierMultiplier: line, 20 | modulatingMultiplier: 5.1 - line, 21 | modulationIndex: line * 6, 22 | amplitude: line / 5 23 | ) 24 | } 25 | engine.output = oscillator 26 | oscillator.start() 27 | let audio = engine.startTest(totalDuration: 1.0) 28 | audio.append(engine.render(duration: 1.0)) 29 | testMD5(audio) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Tests/SporthAudioKitTests/Generator Tests/vocalTractOperationTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | import AudioKit 4 | import SporthAudioKit 5 | import XCTest 6 | 7 | class VocalTractOperationTests: XCTestCase { 8 | func testParameterSweep() { 9 | let engine = AudioEngine() 10 | let vocalTract = OperationGenerator { 11 | let line = Operation.lineSegment( 12 | trigger: Operation.metronome(), 13 | start: 0, 14 | end: 1, 15 | duration: 1.0 16 | ) 17 | return Operation.vocalTract(frequency: 200 + 200 * line, 18 | tonguePosition: line, 19 | tongueDiameter: line, 20 | tenseness: line, 21 | nasality: line) 22 | } 23 | engine.output = vocalTract 24 | vocalTract.start() 25 | let audio = engine.startTest(totalDuration: 1.0) 26 | audio.append(engine.render(duration: 1.0)) 27 | testMD5(audio) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/eval.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "plumber.h" 5 | 6 | int sporth_eval(sporth_stack *stack, void *ud) 7 | { 8 | plumber_data *pd = ud; 9 | plumbing *pipes; 10 | 11 | const char *str; 12 | int rc = PLUMBER_OK; 13 | 14 | switch(pd->mode){ 15 | case PLUMBER_CREATE: 16 | plumber_add_ugen(pd, SPORTH_EVAL, NULL); 17 | if(sporth_check_args(stack, "s") != SPORTH_OK) { 18 | plumber_print(pd, "Not enough arguments for eval.\n"); 19 | return PLUMBER_NOTOK; 20 | } 21 | 22 | str = sporth_stack_pop_string(stack); 23 | pipes = plumber_get_pipes(pd); 24 | rc = plumbing_parse_string(pd, pipes, str); 25 | return rc; 26 | 27 | case PLUMBER_INIT: 28 | sporth_stack_pop_string(stack); 29 | break; 30 | 31 | case PLUMBER_COMPUTE: 32 | break; 33 | 34 | case PLUMBER_DESTROY: 35 | break; 36 | 37 | default: 38 | printf("Error: Unknown mode!"); 39 | break; 40 | } 41 | return PLUMBER_OK; 42 | } 43 | -------------------------------------------------------------------------------- /Sources/SporthAudioKit/Math/Operation+Segments.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | public extension Operation { 4 | /// Line Segment to change values over time 5 | /// 6 | /// - Parameters: 7 | /// - start: Starting value 8 | /// - end: Ending value 9 | /// - duration: Length of time 10 | /// 11 | static func lineSegment( 12 | trigger: Operation, 13 | start: OperationParameter, 14 | end: OperationParameter, 15 | duration: OperationParameter 16 | ) -> Operation { 17 | return Operation(module: "line", inputs: trigger, start, duration, end) 18 | } 19 | 20 | /// Exponential Segment to change values over time 21 | /// 22 | /// - Parameters: 23 | /// - start: Starting value 24 | /// - end: Ending value 25 | /// - duration: Length of time 26 | /// 27 | static func exponentialSegment( 28 | trigger: Operation, 29 | start: OperationParameter, 30 | end: OperationParameter, 31 | duration: OperationParameter 32 | ) -> Operation { 33 | return Operation(module: "expon", inputs: trigger, start, duration, end) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/srand.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "plumber.h" 5 | 6 | int sporth_srand(sporth_stack *stack, void *ud) 7 | { 8 | plumber_data *pd = ud; 9 | uint32_t seed = 0; 10 | 11 | switch(pd->mode){ 12 | case PLUMBER_CREATE: 13 | plumber_add_ugen(pd, SPORTH_SRAND, NULL); 14 | 15 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 16 | plumber_print(pd, "rseed: not enough arguments\n"); 17 | return PLUMBER_NOTOK; 18 | } 19 | #ifdef DEBUG_MODE 20 | plumber_print(pd, "Setting seed to %d\n"); 21 | #endif 22 | seed = (uint32_t)sporth_stack_pop_float(stack); 23 | plumber_print(pd, "seed: %u\n", seed); 24 | sp_srand(pd->sp, seed); 25 | pd->seed = seed; 26 | 27 | break; 28 | 29 | case PLUMBER_INIT: 30 | seed = (uint32_t)sporth_stack_pop_float(stack); 31 | break; 32 | 33 | case PLUMBER_COMPUTE: 34 | seed = (uint32_t)sporth_stack_pop_float(stack); 35 | break; 36 | 37 | case PLUMBER_DESTROY: 38 | break; 39 | 40 | default: 41 | break; 42 | } 43 | return PLUMBER_OK; 44 | } 45 | -------------------------------------------------------------------------------- /SporthAudioKit.playground/Pages/Vocal Tract Operation.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: ## Vocal Tract Operation 2 | //: 3 | //: Sometimes as audio developers, we just like to have some fun. 4 | import AudioKit 5 | import PlaygroundSupport 6 | import SporthAudioKit 7 | 8 | let playRate = 2.0 9 | 10 | let generator = OperationGenerator { _ in 11 | let frequency = Operation.sineWave(frequency: 1).scale(minimum: 100, maximum: 300) 12 | let jitter = Operation.jitter(amplitude: 300, minimumFrequency: 1, maximumFrequency: 3) 13 | let position = Operation.sineWave(frequency: 0.1).scale() 14 | let diameter = Operation.sineWave(frequency: 0.2).scale() 15 | let tenseness = Operation.sineWave(frequency: 0.3).scale() 16 | let nasality = Operation.sineWave(frequency: 0.35).scale() 17 | return Operation.vocalTract(frequency: frequency + jitter, 18 | tonguePosition: position, 19 | tongueDiameter: diameter, 20 | tenseness: tenseness, 21 | nasality: nasality) 22 | } 23 | 24 | let engine = AudioEngine() 25 | engine.output = generator 26 | 27 | try! engine.start() 28 | generator.start() 29 | 30 | PlaygroundPage.current.needsIndefiniteExecution = true 31 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/writecode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "plumber.h" 5 | 6 | int sporth_writecode(sporth_stack *stack, void *ud) 7 | { 8 | plumber_data *pd = ud; 9 | const char *file; 10 | FILE *fp; 11 | switch(pd->mode){ 12 | case PLUMBER_CREATE: 13 | plumber_add_ugen(pd, SPORTH_WRITECODE, NULL); 14 | 15 | if(sporth_check_args(stack, "s") != SPORTH_OK) { 16 | plumber_print(pd, "writecode: not enough arguments\n"); 17 | return PLUMBER_NOTOK; 18 | } 19 | 20 | file = sporth_stack_pop_string(stack); 21 | fp = fopen(file, "w"); 22 | if(fp == NULL) { 23 | plumber_print(pd, "There was a problem opening %s", file); 24 | return PLUMBER_NOTOK; 25 | } 26 | plumber_write_code(pd, fp); 27 | fclose(fp); 28 | 29 | break; 30 | 31 | case PLUMBER_INIT: 32 | sporth_stack_pop_string(stack); 33 | break; 34 | 35 | case PLUMBER_COMPUTE: 36 | break; 37 | 38 | case PLUMBER_DESTROY: 39 | break; 40 | 41 | default: 42 | break; 43 | } 44 | return PLUMBER_OK; 45 | } 46 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/brown.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_brown(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT out; 7 | sp_brown *brown; 8 | 9 | switch(pd->mode) { 10 | case PLUMBER_CREATE: 11 | 12 | #ifdef DEBUG_MODE 13 | plumber_print(pd, "brown: Creating\n"); 14 | #endif 15 | 16 | sp_brown_create(&brown); 17 | plumber_add_ugen(pd, SPORTH_BROWN, brown); 18 | sporth_stack_push_float(stack, 0); 19 | break; 20 | case PLUMBER_INIT: 21 | 22 | #ifdef DEBUG_MODE 23 | plumber_print(pd, "brown: Initialising\n"); 24 | #endif 25 | 26 | brown = pd->last->ud; 27 | sp_brown_init(pd->sp, brown); 28 | sporth_stack_push_float(stack, 0); 29 | break; 30 | case PLUMBER_COMPUTE: 31 | brown = pd->last->ud; 32 | sp_brown_compute(pd->sp, brown, NULL, &out); 33 | sporth_stack_push_float(stack, out); 34 | break; 35 | case PLUMBER_DESTROY: 36 | brown = pd->last->ud; 37 | sp_brown_destroy(&brown); 38 | break; 39 | default: 40 | plumber_print(pd, "brown: Unknown mode!\n"); 41 | break; 42 | } 43 | return PLUMBER_OK; 44 | } 45 | -------------------------------------------------------------------------------- /SporthAudioKit.playground/Pages/LFO.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: ## Low-Frequency Oscillation of Parameters 2 | //: ### Oftentimes we want rhythmic changing of parameters that varying in a standard way. 3 | //: ### This is traditionally done with Low-Frequency Oscillators, LFOs. 4 | //: 5 | import AudioKit 6 | import PlaygroundSupport 7 | import SporthAudioKit 8 | 9 | let generator = OperationGenerator { _ in 10 | let frequencyLFO = Operation.square(frequency: 1) 11 | .scale(minimum: 440, maximum: 880) 12 | let carrierLFO = Operation.triangle(frequency: 1) 13 | .scale(minimum: 1, maximum: 2) 14 | let modulatingMultiplierLFO = Operation.sawtooth(frequency: 1) 15 | .scale(minimum: 0.1, maximum: 2) 16 | let modulatingIndexLFO = Operation.reverseSawtooth(frequency: 1) 17 | .scale(minimum: 0.1, maximum: 20) 18 | 19 | return Operation.fmOscillator( 20 | baseFrequency: frequencyLFO, 21 | carrierMultiplier: carrierLFO, 22 | modulatingMultiplier: modulatingMultiplierLFO, 23 | modulationIndex: modulatingIndexLFO, 24 | amplitude: 0.2 25 | ) 26 | } 27 | 28 | let engine = AudioEngine() 29 | engine.output = generator 30 | 31 | try! engine.start() 32 | generator.start() 33 | 34 | PlaygroundPage.current.needsIndefiniteExecution = true 35 | -------------------------------------------------------------------------------- /Sources/SporthAudioKit/Parameter.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | /// OperationParameters are simply arguments that can be passed into ComputedParameters 4 | /// These could be numbers (floats, doubles, ints) or other operations themselves 5 | /// Since parameters can be audio in mono or stereo format, the protocol 6 | /// requires that an OperationParameter defines method to switch between stereo and mono 7 | public protocol OperationParameter: CustomStringConvertible { 8 | /// Require a function to produce a mono operation regarcless of the mono/stereo nature of the parameter 9 | func toMono() -> Operation 10 | 11 | /// Require a function to produce a stereo operation regardless of the mono/stereo nature of the parameter 12 | func toStereo() -> StereoOperation 13 | } 14 | 15 | /// Default Implementation methods 16 | public extension OperationParameter { 17 | /// Most parameters are mono, so the default is just to return the parameter wrapped in a mono operation 18 | func toMono() -> Operation { 19 | return Operation("\(self) ") 20 | } 21 | 22 | /// Most parameters are mono, so the default is to duplicate the parameter in both stereo channels 23 | func toStereo() -> StereoOperation { 24 | return StereoOperation("\(self) \(self) ") 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/tick.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "plumber.h" 3 | 4 | int sporth_tick(sporth_stack *stack, void *ud) 5 | { 6 | plumber_data *pd = ud; 7 | SPFLOAT out = 0; 8 | int tick = 0; 9 | plumbing *pipes; 10 | switch(pd->mode) { 11 | case PLUMBER_CREATE: 12 | 13 | #ifdef DEBUG_MODE 14 | plumber_print(pd, "tick: Creating\n"); 15 | #endif 16 | plumber_add_ugen(pd, SPORTH_TICK, NULL); 17 | sporth_stack_push_float(stack, 0); 18 | break; 19 | case PLUMBER_INIT: 20 | 21 | #ifdef DEBUG_MODE 22 | plumber_print(pd, "tick: Initialising\n"); 23 | #endif 24 | pipes = plumber_get_pipes(pd); 25 | pipes->tick = 1; 26 | sporth_stack_push_float(stack, 1); 27 | break; 28 | case PLUMBER_COMPUTE: 29 | pipes = plumber_get_pipes(pd); 30 | tick = pipes->tick; 31 | if(tick == 1) { 32 | pipes->tick = 0; 33 | out = 1.0; 34 | } else { 35 | out = 0; 36 | } 37 | sporth_stack_push_float(stack, out); 38 | break; 39 | case PLUMBER_DESTROY: 40 | break; 41 | default: 42 | plumber_print(pd, "tick: Unknown mode!\n"); 43 | break; 44 | } 45 | return PLUMBER_OK; 46 | } 47 | -------------------------------------------------------------------------------- /Demo/Shared/ContentView.swift: -------------------------------------------------------------------------------- 1 | import AudioKit 2 | import AVFoundation 3 | import SwiftUI 4 | 5 | struct ContentView: View { 6 | var body: some View { 7 | NavigationView { 8 | MasterView() 9 | DetailView() 10 | }.navigationViewStyle(DoubleColumnNavigationViewStyle()) 11 | } 12 | } 13 | 14 | struct MasterView: View { 15 | var body: some View { 16 | List { 17 | NavigationLink("Crossing Signal", destination: CrossingSignalView()) 18 | NavigationLink("Drone Operation", destination: DroneOperationView()) 19 | NavigationLink("Instrument Operation", destination: InstrumentOperationView()) 20 | NavigationLink("LFO Operation", destination: LFOOperationView()) 21 | NavigationLink("Phasor Operation", destination: PhasorOperationView()) 22 | NavigationLink("Segment Operation", destination: SegmentOperationView()) 23 | NavigationLink("Stereo Operation", destination: StereoOperationView()) 24 | } 25 | 26 | .navigationTitle("AudioKit") 27 | } 28 | } 29 | 30 | struct DetailView: View { 31 | @State private var opacityValue = 0.0 32 | 33 | var body: some View { 34 | VStack(spacing: 0) { 35 | Text("Please select a recipe from the left-side menu.") 36 | .font(.system(.body, design: .rounded)) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/changed.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "plumber.h" 3 | 4 | int sporth_changed(sporth_stack *stack, void *ud) 5 | { 6 | plumber_data *pd = (plumber_data *)ud; 7 | SPFLOAT *prev; 8 | SPFLOAT val; 9 | 10 | switch(pd->mode) { 11 | case PLUMBER_CREATE: 12 | prev = malloc(sizeof(SPFLOAT)); 13 | plumber_add_ugen(pd, SPORTH_CHANGED, prev); 14 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 15 | stack->error++; 16 | plumber_print(pd, "Invalid arguments for changed\n"); 17 | return PLUMBER_NOTOK; 18 | } 19 | sporth_stack_pop_float(stack); 20 | sporth_stack_push_float(stack, 0); 21 | break; 22 | case PLUMBER_INIT: 23 | sporth_stack_pop_float(stack); 24 | sporth_stack_push_float(stack, 0); 25 | break; 26 | case PLUMBER_COMPUTE: 27 | prev = pd->last->ud; 28 | val = sporth_stack_pop_float(stack); 29 | if(val != *prev) { 30 | sporth_stack_push_float(stack, 1); 31 | } else { 32 | sporth_stack_push_float(stack, 0); 33 | } 34 | *prev = val; 35 | break; 36 | case PLUMBER_DESTROY: 37 | prev = pd->last->ud; 38 | free(prev); 39 | break; 40 | } 41 | return PLUMBER_OK; 42 | } 43 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/scrambler.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "plumber.h" 5 | 6 | int sporth_scrambler(sporth_stack *stack, void *ud) 7 | { 8 | plumber_data *pd = ud; 9 | 10 | sp_ftbl *ft_s, *ft_d; 11 | const char *src, *dst; 12 | 13 | switch(pd->mode){ 14 | case PLUMBER_CREATE: 15 | plumber_add_ugen(pd, SPORTH_SCRAMBLER, NULL); 16 | if(sporth_check_args(stack, "ss") != SPORTH_OK) { 17 | plumber_print(pd, "Init: not enough arguments for gen_line\n"); 18 | return PLUMBER_NOTOK; 19 | } 20 | 21 | src = sporth_stack_pop_string(stack); 22 | dst = sporth_stack_pop_string(stack); 23 | 24 | if(plumber_ftmap_search(pd, src, &ft_s) != PLUMBER_OK) { 25 | plumber_print(pd, 26 | "scrambler: could not find ftable %s", 27 | src); 28 | } 29 | 30 | sp_gen_scrambler(pd->sp, ft_s, &ft_d); 31 | plumber_ftmap_add(pd, dst, ft_d); 32 | break; 33 | 34 | case PLUMBER_INIT: 35 | sporth_stack_pop_string(stack); 36 | sporth_stack_pop_string(stack); 37 | break; 38 | 39 | case PLUMBER_COMPUTE: 40 | break; 41 | 42 | case PLUMBER_DESTROY: 43 | break; 44 | 45 | default: 46 | break; 47 | } 48 | return PLUMBER_OK; 49 | } 50 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/zeros.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "plumber.h" 5 | 6 | int sporth_zeros(sporth_stack *stack, void *ud) 7 | { 8 | plumber_data *pd = ud; 9 | 10 | int size; 11 | sp_ftbl *ft; 12 | const char *str; 13 | 14 | switch(pd->mode){ 15 | case PLUMBER_CREATE: 16 | plumber_add_ugen(pd, SPORTH_ZEROS, NULL); 17 | if(sporth_check_args(stack, "sf") != SPORTH_OK) { 18 | plumber_print(pd, "Init: not enough arguments for zeros\n"); 19 | return PLUMBER_NOTOK; 20 | } 21 | size = (int)sporth_stack_pop_float(stack); 22 | str = sporth_stack_pop_string(stack); 23 | #ifdef DEBUG_MODE 24 | plumber_print(pd, "Zeros: creating table %s of size %d\n", str, size); 25 | #endif 26 | sp_ftbl_create(pd->sp, &ft, size); 27 | plumber_ftmap_add(pd, str, ft); 28 | break; 29 | 30 | case PLUMBER_INIT: 31 | size = (int)sporth_stack_pop_float(stack); 32 | str = sporth_stack_pop_string(stack); 33 | break; 34 | 35 | case PLUMBER_COMPUTE: 36 | size = (int)sporth_stack_pop_float(stack); 37 | break; 38 | 39 | case PLUMBER_DESTROY: 40 | break; 41 | 42 | default: 43 | plumber_print(pd, "Error: Unknown mode!\n"); 44 | break; 45 | } 46 | return PLUMBER_OK; 47 | } 48 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/metro.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_metro(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | 7 | SPFLOAT freq; 8 | SPFLOAT out; 9 | sp_metro *data; 10 | switch(pd->mode){ 11 | case PLUMBER_CREATE: 12 | sp_metro_create(&data); 13 | plumber_add_ugen(pd, SPORTH_METRO, data); 14 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 15 | plumber_print(pd,"Not enough arguments for metro\n"); 16 | stack->error++; 17 | return PLUMBER_NOTOK; 18 | } 19 | freq = sporth_stack_pop_float(stack); 20 | sporth_stack_push_float(stack, 0); 21 | break; 22 | case PLUMBER_INIT: 23 | data = pd->last->ud; 24 | sp_metro_init(pd->sp, data); 25 | sporth_stack_push_float(stack, 0); 26 | break; 27 | case PLUMBER_COMPUTE: 28 | freq = sporth_stack_pop_float(stack); 29 | data = pd->last->ud; 30 | data->freq = freq; 31 | sp_metro_compute(pd->sp, data, NULL, &out); 32 | sporth_stack_push_float(stack, out); 33 | break; 34 | case PLUMBER_DESTROY: 35 | data = pd->last->ud; 36 | sp_metro_destroy(&data); 37 | break; 38 | default: 39 | plumber_print(pd,"Error: Unknown mode!"); 40 | break; 41 | } 42 | return PLUMBER_OK; 43 | } 44 | -------------------------------------------------------------------------------- /Sources/SporthAudioKit/MixingOperations.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | /// Mix together two parameters 4 | /// 5 | /// - Parameters: 6 | /// - first: First parameter 7 | /// - second: Second parameter 8 | /// - balance: Value from zero to one indicating balance between first (0) and second (1) (Default: 0.5) 9 | /// 10 | public func mixer(_ first: OperationParameter, _ second: OperationParameter, balance: OperationParameter = 0.5) -> Operation { 11 | return Operation(module: "1 swap - cf", inputs: first, second, balance) 12 | } 13 | 14 | public extension ComputedParameter { 15 | /// Panner 16 | /// 17 | /// - Parameters: 18 | /// - input: Input audio signal 19 | /// - pan: Panning. A value of -1 is hard left, and a value of 1 is hard right, and 0 is center. 20 | /// (Default: 0, Minimum: -1, Maximum: 1) 21 | /// 22 | func pan(_ pan: OperationParameter = 0) -> StereoOperation { 23 | return StereoOperation(module: "pan", inputs: toMono(), pan) 24 | } 25 | 26 | /// Stereo Panner 27 | /// 28 | /// - Parameters: 29 | /// - input: Input stereo audio signal 30 | /// - pan: Panning. A value of -1 is hard left, and a value of 1 is hard right, and 0 is center. 31 | /// (Default: 0, Minimum: -1, Maximum: 1) 32 | /// 33 | func stereoPan(_ pan: OperationParameter = 0) -> StereoOperation { 34 | return StereoOperation(module: "panst", inputs: toStereo(), pan) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SporthAudioKit.playground/Pages/Plucked String Operation.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: ## Plucked String Operation 2 | //: Experimenting with a physical model of a string 3 | //: 4 | import AudioKit 5 | import Foundation 6 | import PlaygroundSupport 7 | import SporthAudioKit 8 | let playRate = 2.0 9 | 10 | let pluckNode = OperationGenerator { parameters in 11 | let frequency = (Operation.parameters[0] + 40).midiNoteToFrequency() 12 | return Operation.pluckedString( 13 | trigger: Operation.trigger, 14 | frequency: frequency, 15 | amplitude: 0.5, 16 | lowestFrequency: 50 17 | ) 18 | } 19 | 20 | var delay = Delay(pluckNode) 21 | delay.time = Float(1.5 / playRate) 22 | delay.dryWetMix = 50 23 | delay.feedback = 20 24 | 25 | let reverb = Reverb(delay) 26 | 27 | let scale = [0, 2, 4, 5, 7, 9, 11, 12] 28 | 29 | let engine = AudioEngine() 30 | engine.output = reverb 31 | 32 | try! engine.start() 33 | pluckNode.start() 34 | 35 | let t = Timer.scheduledTimer(withTimeInterval: 1.0 / playRate, repeats: true) { _ in 36 | 37 | var note = scale.randomElement()! 38 | let octave = [0, 1, 2, 3].randomElement()! * 12 39 | if (0 ... 10).randomElement()! < 1 { note += 1 } 40 | if !scale.contains(note % 12) { Log("ACCIDENT!") } 41 | 42 | if (0 ... 6).randomElement()! > 1 { 43 | pluckNode.$parameter1.value = AUValue(note + octave) 44 | pluckNode.trigger() 45 | } 46 | } 47 | 48 | PlaygroundPage.current.needsIndefiniteExecution = true 49 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/gen_sine.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "plumber.h" 5 | 6 | int sporth_gen_sine(sporth_stack *stack, void *ud) 7 | { 8 | plumber_data *pd = ud; 9 | 10 | int size; 11 | sp_ftbl *ft; 12 | const char *str; 13 | 14 | switch(pd->mode){ 15 | case PLUMBER_CREATE: 16 | plumber_add_ugen(pd, SPORTH_GEN_SINE, NULL); 17 | 18 | if(sporth_check_args(stack, "sf") != SPORTH_OK) { 19 | plumber_print(pd, "Init: not enough arguments for gen_sine\n"); 20 | return PLUMBER_NOTOK; 21 | } 22 | size = (int)sporth_stack_pop_float(stack); 23 | str = sporth_stack_pop_string(stack); 24 | #ifdef DEBUG_MODE 25 | plumber_print(pd, "Creating sine table %s of size %d\n", str, size); 26 | #endif 27 | sp_ftbl_create(pd->sp, &ft, size); 28 | sp_gen_sine(pd->sp, ft); 29 | plumber_ftmap_add(pd, str, ft); 30 | break; 31 | 32 | case PLUMBER_INIT: 33 | size = (int)sporth_stack_pop_float(stack); 34 | str = sporth_stack_pop_string(stack); 35 | break; 36 | 37 | case PLUMBER_COMPUTE: 38 | size = (int)sporth_stack_pop_float(stack); 39 | break; 40 | 41 | case PLUMBER_DESTROY: 42 | break; 43 | 44 | default: 45 | printf("Error: Unknown mode!"); 46 | break; 47 | } 48 | return PLUMBER_OK; 49 | } 50 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/tog.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "plumber.h" 3 | 4 | 5 | int sporth_tog(sporth_stack *stack, void *ud) 6 | { 7 | plumber_data *pd = ud; 8 | SPFLOAT trig = 0; 9 | SPFLOAT *val; 10 | switch(pd->mode){ 11 | case PLUMBER_CREATE: 12 | val = malloc(sizeof(SPFLOAT)); 13 | plumber_add_ugen(pd, SPORTH_TOG, val); 14 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 15 | stack->error++; 16 | plumber_print(pd,"Invalid arguments for tog.\n"); 17 | return PLUMBER_NOTOK; 18 | } 19 | 20 | trig = sporth_stack_pop_float(stack); 21 | sporth_stack_push_float(stack, 0); 22 | break; 23 | case PLUMBER_INIT: 24 | val = pd->last->ud; 25 | trig = sporth_stack_pop_float(stack); 26 | 27 | *val = 0; 28 | sporth_stack_push_float(stack, *val); 29 | break; 30 | case PLUMBER_COMPUTE: 31 | val = pd->last->ud; 32 | trig = sporth_stack_pop_float(stack); 33 | if(trig != 0) { 34 | *val = (*val == 0) ? 1 : 0; 35 | } 36 | sporth_stack_push_float(stack, *val); 37 | break; 38 | case PLUMBER_DESTROY: 39 | val = pd->last->ud; 40 | free(val); 41 | break; 42 | default: 43 | printf("Error: Unknown mode!"); 44 | break; 45 | } 46 | return PLUMBER_OK; 47 | } 48 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/gen_rand.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "plumber.h" 6 | 7 | int sporth_gen_rand(sporth_stack *stack, void *ud) 8 | { 9 | plumber_data *pd = ud; 10 | 11 | uint32_t size; 12 | sp_ftbl *ft; 13 | const char *str, *args; 14 | 15 | switch(pd->mode){ 16 | case PLUMBER_CREATE: 17 | plumber_add_ugen(pd, SPORTH_GEN_RAND, NULL); 18 | 19 | if(sporth_check_args(stack, "sfs") != SPORTH_OK) { 20 | plumber_print(pd, 21 | "gen_rand: not enough arguments for gen_rand\n"); 22 | return PLUMBER_NOTOK; 23 | } 24 | 25 | args = sporth_stack_pop_string(stack); 26 | size = (uint32_t)sporth_stack_pop_float(stack); 27 | str = sporth_stack_pop_string(stack); 28 | 29 | sp_ftbl_create(pd->sp, &ft, size); 30 | 31 | sp_gen_rand(pd->sp, ft, args); 32 | 33 | plumber_ftmap_add(pd, str, ft); 34 | break; 35 | 36 | case PLUMBER_INIT: 37 | sporth_stack_pop_string(stack); 38 | sporth_stack_pop_float(stack); 39 | sporth_stack_pop_string(stack); 40 | break; 41 | 42 | case PLUMBER_COMPUTE: 43 | sporth_stack_pop_float(stack); 44 | break; 45 | 46 | case PLUMBER_DESTROY: 47 | break; 48 | 49 | default: 50 | plumber_print(pd,"Error: Unknown mode!"); 51 | break; 52 | } 53 | return PLUMBER_OK; 54 | } 55 | -------------------------------------------------------------------------------- /SporthAudioKit.playground/Pages/FM Oscillator Operation.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: ## FM Oscillator Operation 2 | //: 3 | import AudioKit 4 | import PlaygroundSupport 5 | import SporthAudioKit 6 | 7 | let generator = OperationGenerator { _ in 8 | 9 | // Set up the operations that will be used to make a generator node 10 | let sine = Operation.sineWave(frequency: 1) 11 | let square = Operation.squareWave(frequency: 1.64) 12 | let square2 = Operation.squareWave(frequency: sine, amplitude: sine, pulseWidth: sine) 13 | 14 | let freq = sine.scale(minimum: 900, maximum: 200) 15 | let car = square.scale(minimum: 1.2, maximum: 1.4) 16 | let mod = square.scale(minimum: 1, maximum: 3) 17 | let index = square2 * 3 + 5 18 | 19 | let oscillator = Operation.fmOscillator(baseFrequency: freq, 20 | carrierMultiplier: car, 21 | modulatingMultiplier: mod, 22 | modulationIndex: index, 23 | amplitude: 0.5) 24 | 25 | return oscillator.pan(sine) 26 | } 27 | 28 | let delay1 = Delay(generator, time: 0.01, feedback: 0.99, lowPassCutoff: 0, dryWetMix: 0.5) 29 | let delay2 = Delay(delay1, time: 0.1, feedback: 0.1, lowPassCutoff: 0, dryWetMix: 0.5) 30 | let reverb = Reverb(delay2, dryWetMix: 0.5) 31 | 32 | let engine = AudioEngine() 33 | engine.output = reverb 34 | 35 | try! engine.start() 36 | generator.start() 37 | 38 | PlaygroundPage.current.needsIndefiniteExecution = true 39 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/dcblock.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_dcblock(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | 7 | SPFLOAT out; 8 | SPFLOAT in; 9 | sp_dcblock *data; 10 | switch(pd->mode){ 11 | case PLUMBER_CREATE: 12 | #ifdef DEBUG_MODE 13 | plumber_print(pd, "Creating module dcblk\n"); 14 | #endif 15 | sp_dcblock_create(&data); 16 | plumber_add_ugen(pd, SPORTH_DCBLK, data); 17 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 18 | plumber_print(pd, "Not enough arguments for dcblk\n"); 19 | stack->error++; 20 | return PLUMBER_NOTOK; 21 | } 22 | in = sporth_stack_pop_float(stack); 23 | sporth_stack_push_float(stack, 0); 24 | break; 25 | case PLUMBER_INIT: 26 | data = pd->last->ud; 27 | in = sporth_stack_pop_float(stack); 28 | sp_dcblock_init(pd->sp, data); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_COMPUTE: 32 | data = pd->last->ud; 33 | in = sporth_stack_pop_float(stack); 34 | sp_dcblock_compute(pd->sp, data, &in, &out); 35 | sporth_stack_push_float(stack, out); 36 | break; 37 | case PLUMBER_DESTROY: 38 | data = pd->last->ud; 39 | sp_dcblock_destroy(&data); 40 | break; 41 | default: 42 | printf("Error: Unknown mode!"); 43 | break; 44 | } 45 | return PLUMBER_OK; 46 | } 47 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/gen_composite.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "plumber.h" 6 | 7 | int sporth_gen_composite(sporth_stack *stack, void *ud) 8 | { 9 | plumber_data *pd = ud; 10 | 11 | uint32_t size; 12 | sp_ftbl *ft; 13 | const char *str, *args; 14 | 15 | switch(pd->mode){ 16 | case PLUMBER_CREATE: 17 | plumber_add_ugen(pd, SPORTH_GEN_COMPOSITE, NULL); 18 | 19 | if(sporth_check_args(stack, "sfs") != SPORTH_OK) { 20 | plumber_print(pd, 21 | "composite: not enough arguments for gen_composite\n"); 22 | return PLUMBER_NOTOK; 23 | } 24 | 25 | args = sporth_stack_pop_string(stack); 26 | size = (uint32_t)sporth_stack_pop_float(stack); 27 | str = sporth_stack_pop_string(stack); 28 | 29 | sp_ftbl_create(pd->sp, &ft, size); 30 | 31 | sp_gen_composite(pd->sp, ft, args); 32 | 33 | plumber_ftmap_add(pd, str, ft); 34 | break; 35 | 36 | case PLUMBER_INIT: 37 | args = sporth_stack_pop_string(stack); 38 | size = (uint32_t)sporth_stack_pop_float(stack); 39 | str = sporth_stack_pop_string(stack); 40 | break; 41 | 42 | case PLUMBER_COMPUTE: 43 | sporth_stack_pop_float(stack); 44 | break; 45 | 46 | case PLUMBER_DESTROY: 47 | break; 48 | 49 | default: 50 | plumber_print(pd,"Error: Unknown mode!"); 51 | break; 52 | } 53 | return PLUMBER_OK; 54 | } 55 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/load.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "plumber.h" 5 | 6 | int sporth_load(sporth_stack *stack, void *ud) 7 | { 8 | plumber_data *pd = ud; 9 | plumbing *pipes; 10 | 11 | FILE *tmp, *fp; 12 | const char *filename; 13 | int rc = PLUMBER_OK; 14 | 15 | switch(pd->mode){ 16 | case PLUMBER_CREATE: 17 | plumber_add_ugen(pd, SPORTH_LOAD, NULL); 18 | if(sporth_check_args(stack, "s") != SPORTH_OK) { 19 | plumber_print(pd, "Not enough arguments for load.\n"); 20 | return PLUMBER_NOTOK; 21 | } 22 | 23 | filename = sporth_stack_pop_string(stack); 24 | fp = fopen(filename, "r"); 25 | if(fp == NULL) { 26 | plumber_print(pd, 27 | "There was an issue opening the file \"%s\"\n", 28 | filename); 29 | return PLUMBER_NOTOK; 30 | } 31 | tmp = pd->fp; 32 | pd->fp = fp; 33 | pipes = plumber_get_pipes(pd); 34 | rc = plumbing_parse(pd, pipes); 35 | fclose(fp); 36 | pd->fp = tmp; 37 | return rc; 38 | 39 | case PLUMBER_INIT: 40 | filename = sporth_stack_pop_string(stack); 41 | break; 42 | 43 | case PLUMBER_COMPUTE: 44 | break; 45 | 46 | case PLUMBER_DESTROY: 47 | break; 48 | 49 | default: 50 | printf("Error: Unknown mode!"); 51 | break; 52 | } 53 | return PLUMBER_OK; 54 | } 55 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/noise.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_noise(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | 7 | SPFLOAT amp; 8 | SPFLOAT out; 9 | sp_noise *data; 10 | switch(pd->mode){ 11 | case PLUMBER_CREATE: 12 | sp_noise_create(&data); 13 | plumber_add_ugen(pd, SPORTH_NOISE, data); 14 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 15 | plumber_print(pd, "Not enough arguments for noise\n"); 16 | stack->error++; 17 | return PLUMBER_NOTOK; 18 | } 19 | amp = sporth_stack_pop_float(stack); 20 | sporth_stack_push_float(stack, 0); 21 | break; 22 | case PLUMBER_INIT: 23 | data = pd->last->ud; 24 | amp = sporth_stack_pop_float(stack); 25 | if(sp_noise_init(pd->sp, data) == SP_NOT_OK) { 26 | stack->error++; 27 | return PLUMBER_NOTOK; 28 | } 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_COMPUTE: 32 | amp = sporth_stack_pop_float(stack); 33 | data = pd->last->ud; 34 | data->amp = amp; 35 | sp_noise_compute(pd->sp, data, NULL, &out); 36 | sporth_stack_push_float(stack, out); 37 | break; 38 | case PLUMBER_DESTROY: 39 | data = pd->last->ud; 40 | sp_noise_destroy(&data); 41 | break; 42 | default: 43 | printf("Error: Unknown mode!"); 44 | break; 45 | } 46 | return PLUMBER_OK; 47 | } 48 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/gen_vals.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "plumber.h" 6 | 7 | int sporth_gen_vals(sporth_stack *stack, void *ud) 8 | { 9 | plumber_data *pd = ud; 10 | 11 | sp_ftbl *ft; 12 | const char *str, *args; 13 | 14 | switch(pd->mode){ 15 | case PLUMBER_CREATE: 16 | plumber_add_ugen(pd, SPORTH_GEN_VALS, NULL); 17 | 18 | if(sporth_check_args(stack, "ss") != SPORTH_OK) { 19 | plumber_print(pd,"Init: not enough arguments for gen_vals\n"); 20 | return PLUMBER_NOTOK; 21 | } 22 | 23 | args = sporth_stack_pop_string(stack); 24 | str = sporth_stack_pop_string(stack); 25 | 26 | #ifdef DEBUG_MODE 27 | plumber_print(pd,"Creating value table %s\n", str + 1); 28 | #endif 29 | sp_ftbl_create(pd->sp, &ft, 1); 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd,"Running gen_val function\n"); 33 | #endif 34 | sp_gen_vals(pd->sp, ft, args); 35 | 36 | #ifdef DEBUG_MODE 37 | plumber_print(pd,"Adding ftable\n"); 38 | #endif 39 | 40 | plumber_ftmap_add(pd, str, ft); 41 | 42 | break; 43 | 44 | case PLUMBER_INIT: 45 | args = sporth_stack_pop_string(stack); 46 | str = sporth_stack_pop_string(stack); 47 | break; 48 | 49 | case PLUMBER_COMPUTE: 50 | break; 51 | 52 | case PLUMBER_DESTROY: 53 | break; 54 | 55 | default: 56 | plumber_print(pd,"Error: Unknown mode!"); 57 | break; 58 | } 59 | return PLUMBER_OK; 60 | } 61 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/rms.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_rms(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT in; 7 | SPFLOAT out; 8 | sp_rms *rms; 9 | 10 | switch(pd->mode) { 11 | case PLUMBER_CREATE: 12 | 13 | #ifdef DEBUG_MODE 14 | plumber_print(pd, "rms: Creating\n"); 15 | #endif 16 | 17 | sp_rms_create(&rms); 18 | plumber_add_ugen(pd, SPORTH_RMS, rms); 19 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 20 | plumber_print(pd,"Not enough arguments for rms\n"); 21 | stack->error++; 22 | return PLUMBER_NOTOK; 23 | } 24 | in = sporth_stack_pop_float(stack); 25 | sporth_stack_push_float(stack, 0); 26 | break; 27 | case PLUMBER_INIT: 28 | 29 | #ifdef DEBUG_MODE 30 | plumber_print(pd, "rms: Initialising\n"); 31 | #endif 32 | in = sporth_stack_pop_float(stack); 33 | rms = pd->last->ud; 34 | sp_rms_init(pd->sp, rms); 35 | sporth_stack_push_float(stack, 0); 36 | break; 37 | case PLUMBER_COMPUTE: 38 | in = sporth_stack_pop_float(stack); 39 | rms = pd->last->ud; 40 | sp_rms_compute(pd->sp, rms, &in, &out); 41 | sporth_stack_push_float(stack, out); 42 | break; 43 | case PLUMBER_DESTROY: 44 | rms = pd->last->ud; 45 | sp_rms_destroy(&rms); 46 | break; 47 | default: 48 | plumber_print(pd, "rms: Unknown mode!\n"); 49 | break; 50 | } 51 | return PLUMBER_OK; 52 | } 53 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/tin.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_tin(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT trig; 7 | SPFLOAT out; 8 | sp_tin *tin; 9 | 10 | switch(pd->mode) { 11 | case PLUMBER_CREATE: 12 | 13 | #ifdef DEBUG_MODE 14 | plumber_print(pd, "tin: Creating\n"); 15 | #endif 16 | 17 | sp_tin_create(&tin); 18 | plumber_add_ugen(pd, SPORTH_TIN, tin); 19 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 20 | plumber_print(pd,"Not enough arguments for tin\n"); 21 | stack->error++; 22 | return PLUMBER_NOTOK; 23 | } 24 | trig = sporth_stack_pop_float(stack); 25 | sporth_stack_push_float(stack, 0); 26 | break; 27 | case PLUMBER_INIT: 28 | 29 | #ifdef DEBUG_MODE 30 | plumber_print(pd, "tin: Initialising\n"); 31 | #endif 32 | trig = sporth_stack_pop_float(stack); 33 | tin = pd->last->ud; 34 | sp_tin_init(pd->sp, tin); 35 | sporth_stack_push_float(stack, 0); 36 | break; 37 | case PLUMBER_COMPUTE: 38 | trig = sporth_stack_pop_float(stack); 39 | tin = pd->last->ud; 40 | sp_tin_compute(pd->sp, tin, &trig, &out); 41 | sporth_stack_push_float(stack, out); 42 | break; 43 | case PLUMBER_DESTROY: 44 | tin = pd->last->ud; 45 | sp_tin_destroy(&tin); 46 | break; 47 | default: 48 | plumber_print(pd, "tin: Unknown mode!\n"); 49 | break; 50 | } 51 | return PLUMBER_OK; 52 | } 53 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/jcrev.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_jcrev(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT out; 8 | sp_jcrev *jcrev; 9 | 10 | switch(pd->mode) { 11 | case PLUMBER_CREATE: 12 | 13 | #ifdef DEBUG_MODE 14 | plumber_print(pd, "jcrev: Creating\n"); 15 | #endif 16 | 17 | sp_jcrev_create(&jcrev); 18 | plumber_add_ugen(pd, SPORTH_JCREV, jcrev); 19 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 20 | plumber_print(pd,"Not enough arguments for jcrev\n"); 21 | stack->error++; 22 | return PLUMBER_NOTOK; 23 | } 24 | input = sporth_stack_pop_float(stack); 25 | sporth_stack_push_float(stack, 0); 26 | break; 27 | case PLUMBER_INIT: 28 | 29 | #ifdef DEBUG_MODE 30 | plumber_print(pd, "jcrev: Initialising\n"); 31 | #endif 32 | input = sporth_stack_pop_float(stack); 33 | jcrev = pd->last->ud; 34 | sp_jcrev_init(pd->sp, jcrev); 35 | sporth_stack_push_float(stack, 0); 36 | break; 37 | case PLUMBER_COMPUTE: 38 | input = sporth_stack_pop_float(stack); 39 | jcrev = pd->last->ud; 40 | sp_jcrev_compute(pd->sp, jcrev, &input, &out); 41 | sporth_stack_push_float(stack, out); 42 | break; 43 | case PLUMBER_DESTROY: 44 | jcrev = pd->last->ud; 45 | sp_jcrev_destroy(&jcrev); 46 | break; 47 | default: 48 | plumber_print(pd, "jcrev: Unknown mode!\n"); 49 | break; 50 | } 51 | return PLUMBER_OK; 52 | } 53 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/timer.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_timer(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT clock; 7 | SPFLOAT out; 8 | sp_timer *timer; 9 | 10 | switch(pd->mode) { 11 | case PLUMBER_CREATE: 12 | 13 | #ifdef DEBUG_MODE 14 | plumber_print(pd, "timer: Creating\n"); 15 | #endif 16 | 17 | sp_timer_create(&timer); 18 | plumber_add_ugen(pd, SPORTH_TIMER, timer); 19 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 20 | plumber_print(pd,"Not enough arguments for timer\n"); 21 | stack->error++; 22 | return PLUMBER_NOTOK; 23 | } 24 | clock = sporth_stack_pop_float(stack); 25 | sporth_stack_push_float(stack, 0); 26 | break; 27 | case PLUMBER_INIT: 28 | 29 | #ifdef DEBUG_MODE 30 | plumber_print(pd, "timer: Initialising\n"); 31 | #endif 32 | 33 | clock = sporth_stack_pop_float(stack); 34 | timer = pd->last->ud; 35 | sp_timer_init(pd->sp, timer); 36 | sporth_stack_push_float(stack, 0); 37 | break; 38 | case PLUMBER_COMPUTE: 39 | clock = sporth_stack_pop_float(stack); 40 | timer = pd->last->ud; 41 | sp_timer_compute(pd->sp, timer, &clock, &out); 42 | sporth_stack_push_float(stack, out); 43 | break; 44 | case PLUMBER_DESTROY: 45 | timer = pd->last->ud; 46 | sp_timer_destroy(&timer); 47 | break; 48 | default: 49 | plumber_print(pd, "timer: Unknown mode!\n"); 50 | break; 51 | } 52 | return PLUMBER_OK; 53 | } 54 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: [main] 7 | pull_request: 8 | branches: [main] 9 | 10 | jobs: 11 | swift_test: 12 | name: Test 13 | uses: AudioKit/ci/.github/workflows/swift_test.yml@main 14 | with: 15 | scheme: SporthAudioKit 16 | platforms: iOS macOS tvOS 17 | swift-versions: 5.5 5.6 18 | 19 | build_demo: 20 | name: Build ${{ matrix.scheme }} (Xcode ${{ matrix.xcode_version }}) 21 | # NOTE: macos-latest is NOT equivalent to macos-12 as of September 2022. 22 | # Source: https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources 23 | runs-on: macos-12 24 | needs: [swift_test] 25 | strategy: 26 | # Disabling fail-fast ensures that the job will run all configurations of the matrix, even if one fails. 27 | fail-fast: false 28 | matrix: 29 | scheme: 30 | - SporthAudioKitDemo (iOS) 31 | - SporthAudioKitDemo (macOS) 32 | xcode_version: 33 | - '13.2' # swift 5.5 34 | - '13.4' # swift 5.6 35 | steps: 36 | - name: Build Demo 37 | uses: AudioKit/ci/.github/actions/build-demo@main 38 | with: 39 | project: Demo/SporthAudioKitDemo.xcodeproj 40 | scheme: ${{ matrix.scheme }} 41 | xcode_version: ${{ matrix.xcode_version }} 42 | 43 | # Send notification to Discord on failure. 44 | send_notification: 45 | name: Send Notification 46 | uses: AudioKit/ci/.github/workflows/send_notification.yml@main 47 | needs: [swift_test, build_demo] 48 | if: ${{ failure() && github.ref == 'refs/heads/main' }} 49 | secrets: inherit 50 | -------------------------------------------------------------------------------- /Demo/Shared/Operations/StereoOperation.swift: -------------------------------------------------------------------------------- 1 | import AudioKit 2 | import AudioKitUI 3 | import SporthAudioKit 4 | import SwiftUI 5 | 6 | class StereoOperationConductor: ObservableObject, HasAudioEngine { 7 | let engine = AudioEngine() 8 | 9 | @Published var isRunning = false { 10 | didSet { 11 | isRunning ? generator.start() : generator.stop() 12 | } 13 | } 14 | 15 | let generator = OperationGenerator(channelCount: 2) { _ in 16 | 17 | let slowSine = round(Operation.sineWave(frequency: 1) * 12) / 12 18 | let vibrato = slowSine.scale(minimum: -1200, maximum: 1200) 19 | 20 | let fastSine = Operation.sineWave(frequency: 10) 21 | let volume = fastSine.scale(minimum: 0, maximum: 0.5) 22 | 23 | let leftOutput = Operation.sineWave(frequency: 440 + vibrato, amplitude: volume) 24 | let rightOutput = Operation.sineWave(frequency: 220 + vibrato, amplitude: volume) 25 | 26 | return [leftOutput, rightOutput] 27 | } 28 | 29 | init() { 30 | engine.output = generator 31 | } 32 | } 33 | 34 | struct StereoOperationView: View { 35 | @StateObject var conductor = StereoOperationConductor() 36 | 37 | var body: some View { 38 | VStack(spacing: 50) { 39 | Text("This is an example of building a stereo sound generator.") 40 | Text(conductor.isRunning ? "Stop" : "Start").onTapGesture { 41 | conductor.isRunning.toggle() 42 | } 43 | NodeOutputView(conductor.generator) 44 | } 45 | .padding() 46 | .navigationTitle("Stereo Operation") 47 | .onAppear { 48 | conductor.start() 49 | } 50 | .onDisappear { 51 | conductor.stop() 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/dmetro.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_dmetro(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT out; 7 | SPFLOAT time; 8 | sp_dmetro *dmetro; 9 | 10 | switch(pd->mode) { 11 | case PLUMBER_CREATE: 12 | 13 | #ifdef DEBUG_MODE 14 | plumber_print(pd, "dmetro: Creating\n"); 15 | #endif 16 | 17 | sp_dmetro_create(&dmetro); 18 | plumber_add_ugen(pd, SPORTH_DMETRO, dmetro); 19 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 20 | plumber_print(pd,"Not enough arguments for dmetro\n"); 21 | stack->error++; 22 | return PLUMBER_NOTOK; 23 | } 24 | time = sporth_stack_pop_float(stack); 25 | sporth_stack_push_float(stack, 0); 26 | break; 27 | case PLUMBER_INIT: 28 | 29 | #ifdef DEBUG_MODE 30 | plumber_print(pd, "dmetro: Initialising\n"); 31 | #endif 32 | 33 | time = sporth_stack_pop_float(stack); 34 | dmetro = pd->last->ud; 35 | sp_dmetro_init(pd->sp, dmetro); 36 | sporth_stack_push_float(stack, 0); 37 | break; 38 | case PLUMBER_COMPUTE: 39 | time = sporth_stack_pop_float(stack); 40 | dmetro = pd->last->ud; 41 | dmetro->time = time; 42 | sp_dmetro_compute(pd->sp, dmetro, NULL, &out); 43 | sporth_stack_push_float(stack, out); 44 | break; 45 | case PLUMBER_DESTROY: 46 | dmetro = pd->last->ud; 47 | sp_dmetro_destroy(&dmetro); 48 | break; 49 | default: 50 | plumber_print(pd, "dmetro: Unknown mode!\n"); 51 | break; 52 | } 53 | return PLUMBER_OK; 54 | } 55 | -------------------------------------------------------------------------------- /Demo/Shared/Operations/DroneOperation.swift: -------------------------------------------------------------------------------- 1 | import AudioKit 2 | import AudioKitUI 3 | import SporthAudioKit 4 | import SwiftUI 5 | 6 | class DroneOperationConductor: ObservableObject, HasAudioEngine { 7 | let engine = AudioEngine() 8 | 9 | @Published var isRunning = false { 10 | didSet { 11 | isRunning ? generator.start() : generator.stop() 12 | } 13 | } 14 | 15 | let generator = OperationGenerator { 16 | func drone(frequency: Double, rate: Double) -> OperationParameter { 17 | let metro = Operation.metronome(frequency: rate) 18 | let tone = Operation.sineWave(frequency: frequency, amplitude: 0.2) 19 | return tone.triggeredWithEnvelope(trigger: metro, attack: 0.01, hold: 0.1, release: 0.1) 20 | } 21 | 22 | let drone1 = drone(frequency: 440, rate: 3) 23 | let drone2 = drone(frequency: 330, rate: 5) 24 | let drone3 = drone(frequency: 450, rate: 7) 25 | 26 | return (drone1 + drone2 + drone3) / 3 27 | } 28 | 29 | init() { 30 | engine.output = generator 31 | } 32 | } 33 | 34 | struct DroneOperationView: View { 35 | @StateObject var conductor = DroneOperationConductor() 36 | 37 | var body: some View { 38 | VStack(spacing: 50) { 39 | Text("Encapsualating functionality of operations into functions") 40 | Text(conductor.isRunning ? "Stop" : "Start").onTapGesture { 41 | conductor.isRunning.toggle() 42 | } 43 | NodeOutputView(conductor.generator) 44 | } 45 | .padding() 46 | .navigationTitle("Drone Operation") 47 | .onAppear { 48 | conductor.start() 49 | } 50 | .onDisappear { 51 | conductor.stop() 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Tests/CSporthAudioKitTests/SoundpipePerfTests.mm: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import 7 | 8 | @interface SoundpipePerfTests : XCTestCase 9 | 10 | @end 11 | 12 | @implementation SoundpipePerfTests 13 | 14 | static int sampleRate = 44100; 15 | static int channelCount = 2; 16 | static int iterations = 60 * 44100; 17 | 18 | - (void) testOscPerf { 19 | 20 | sp_data *sp; 21 | sp_create(&sp); 22 | sp->sr = sampleRate; 23 | sp->nchan = channelCount; 24 | 25 | sp_ftbl *ftbl; 26 | sp_ftbl_create(sp, &ftbl, 8192); 27 | sp_gen_triangle(sp, ftbl); 28 | 29 | sp_osc *osc; 30 | sp_osc_create(&osc); 31 | sp_osc_init(sp, osc, ftbl, 0); 32 | 33 | osc->freq = 440; 34 | 35 | [self measureBlock:^{ 36 | for(int i=0;isr = sampleRate; 52 | sp->nchan = channelCount; 53 | 54 | plumber_data pd; 55 | plumber_register(&pd); 56 | plumber_init(&pd); 57 | 58 | pd.sp = sp; 59 | plumber_parse_string(&pd, "440 1 sine"); 60 | plumber_compute(&pd, PLUMBER_INIT); 61 | 62 | auto *pdp = &pd; 63 | 64 | [self measureBlock:^{ 65 | for(int i=0;isporth.stack); 68 | } 69 | }]; 70 | 71 | plumber_clean(&pd); 72 | sp_destroy(&sp); 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /Tests/SporthAudioKitTests/Effect Tests/delayOperationTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | import AudioKit 4 | import SoundpipeAudioKit 5 | import SporthAudioKit 6 | import XCTest 7 | 8 | class DelayOperationTests: XCTestCase { 9 | func testDefault() { 10 | let engine = AudioEngine() 11 | let input = Oscillator(waveform: Table(.triangle)) 12 | engine.output = OperationEffect(input) { $0.delay() } 13 | input.start() 14 | let audio = engine.startTest(totalDuration: 5.0) 15 | audio.append(engine.render(duration: 5.0)) 16 | testMD5(audio) 17 | } 18 | 19 | func testFeedback() { 20 | let engine = AudioEngine() 21 | let input = Oscillator(waveform: Table(.triangle)) 22 | engine.output = OperationEffect(input) { $0.delay(feedback: 0.99) } 23 | input.start() 24 | let audio = engine.startTest(totalDuration: 5.0) 25 | audio.append(engine.render(duration: 5.0)) 26 | testMD5(audio) 27 | } 28 | 29 | func testParameters() { 30 | let engine = AudioEngine() 31 | let input = Oscillator(waveform: Table(.triangle)) 32 | engine.output = OperationEffect(input) { $0.delay(time: 0.01, feedback: 0.99) } 33 | input.start() 34 | let audio = engine.startTest(totalDuration: 5.0) 35 | audio.append(engine.render(duration: 5.0)) 36 | testMD5(audio) 37 | } 38 | 39 | func testTime() { 40 | let engine = AudioEngine() 41 | let input = Oscillator(waveform: Table(.triangle)) 42 | engine.output = OperationEffect(input) { $0.delay(time: 0.01) } 43 | input.start() 44 | let audio = engine.startTest(totalDuration: 5.0) 45 | audio.append(engine.render(duration: 5.0)) 46 | testMD5(audio) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/rand.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "plumber.h" 3 | 4 | int sporth_rand(sporth_stack *stack, void *ud) 5 | { 6 | plumber_data *pd = ud; 7 | SPFLOAT min; 8 | SPFLOAT max; 9 | SPFLOAT *val; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "trand: Creating\n"); 16 | #endif 17 | val = malloc(sizeof(SPFLOAT)); 18 | plumber_add_ugen(pd, SPORTH_RAND, val); 19 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 20 | plumber_print(pd,"Not enough arguments for rand\n"); 21 | stack->error++; 22 | return PLUMBER_NOTOK; 23 | } 24 | max = sporth_stack_pop_float(stack); 25 | min = sporth_stack_pop_float(stack); 26 | *val = min + ((SPFLOAT)sp_rand(pd->sp) / SP_RANDMAX) * (max - min); 27 | sporth_stack_push_float(stack, *val); 28 | break; 29 | case PLUMBER_INIT: 30 | #ifdef DEBUG_MODE 31 | plumber_print(pd, "rand: Initialising\n"); 32 | #endif 33 | sporth_stack_pop_float(stack); 34 | sporth_stack_pop_float(stack); 35 | val = pd->last->ud; 36 | sporth_stack_push_float(stack, *val); 37 | break; 38 | case PLUMBER_COMPUTE: 39 | val = pd->last->ud; 40 | sporth_stack_pop_float(stack); 41 | sporth_stack_pop_float(stack); 42 | sporth_stack_push_float(stack, *val); 43 | break; 44 | case PLUMBER_DESTROY: 45 | val = pd->last->ud; 46 | free(val); 47 | break; 48 | default: 49 | plumber_print(pd, "rand: Unknown mode!\n"); 50 | break; 51 | } 52 | return PLUMBER_OK; 53 | } 54 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/pinknoise.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_pinknoise(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT out; 7 | SPFLOAT amp; 8 | sp_pinknoise *pinknoise; 9 | 10 | switch(pd->mode) { 11 | case PLUMBER_CREATE: 12 | 13 | #ifdef DEBUG_MODE 14 | plumber_print(pd, "pinknoise: Creating\n"); 15 | #endif 16 | 17 | sp_pinknoise_create(&pinknoise); 18 | plumber_add_ugen(pd, SPORTH_PINKNOISE, pinknoise); 19 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 20 | plumber_print(pd,"Not enough arguments for pinknoise\n"); 21 | stack->error++; 22 | return PLUMBER_NOTOK; 23 | } 24 | amp = sporth_stack_pop_float(stack); 25 | sporth_stack_push_float(stack, 0); 26 | break; 27 | case PLUMBER_INIT: 28 | 29 | #ifdef DEBUG_MODE 30 | plumber_print(pd, "pinknoise: Initialising\n"); 31 | #endif 32 | 33 | amp = sporth_stack_pop_float(stack); 34 | pinknoise = pd->last->ud; 35 | sp_pinknoise_init(pd->sp, pinknoise); 36 | sporth_stack_push_float(stack, 0); 37 | break; 38 | case PLUMBER_COMPUTE: 39 | amp = sporth_stack_pop_float(stack); 40 | pinknoise = pd->last->ud; 41 | pinknoise->amp = amp; 42 | sp_pinknoise_compute(pd->sp, pinknoise, NULL, &out); 43 | sporth_stack_push_float(stack, out); 44 | break; 45 | case PLUMBER_DESTROY: 46 | pinknoise = pd->last->ud; 47 | sp_pinknoise_destroy(&pinknoise); 48 | break; 49 | default: 50 | plumber_print(pd, "pinknoise: Unknown mode!\n"); 51 | break; 52 | } 53 | return PLUMBER_OK; 54 | } 55 | -------------------------------------------------------------------------------- /Demo/Shared/Operations/CrossingSignal.swift: -------------------------------------------------------------------------------- 1 | import AudioKit 2 | import AudioKitUI 3 | import SporthAudioKit 4 | import SwiftUI 5 | 6 | class CrossingSignalConductor: ObservableObject, HasAudioEngine { 7 | let engine = AudioEngine() 8 | 9 | @Published var isRunning = false { 10 | didSet { 11 | isRunning ? generator.start() : generator.stop() 12 | } 13 | } 14 | 15 | let generator = OperationGenerator { 16 | // Generate a sine wave at the right frequency 17 | let crossingSignalTone = Operation.sineWave(frequency: 2500) 18 | 19 | // Periodically trigger an envelope around that signal 20 | let crossingSignalTrigger = Operation.periodicTrigger(period: 0.2) 21 | let crossingSignal = crossingSignalTone.triggeredWithEnvelope( 22 | trigger: crossingSignalTrigger, 23 | attack: 0.01, 24 | hold: 0.1, 25 | release: 0.01 26 | ) 27 | 28 | // scale the volume 29 | return crossingSignal * 0.2 30 | } 31 | 32 | init() { 33 | engine.output = generator 34 | } 35 | } 36 | 37 | struct CrossingSignalView: View { 38 | @StateObject var conductor = CrossingSignalConductor() 39 | 40 | var body: some View { 41 | VStack(spacing: 50) { 42 | Text("A British crossing signal implemented with AudioKit, an example from Andy Farnell's excellent book \"Designing Sound\"") 43 | Text(conductor.isRunning ? "Stop" : "Start").onTapGesture { 44 | conductor.isRunning.toggle() 45 | } 46 | NodeOutputView(conductor.generator) 47 | } 48 | .padding() 49 | .navigationTitle("Crossing Signal") 50 | .onAppear { 51 | conductor.start() 52 | } 53 | .onDisappear { 54 | conductor.stop() 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/bal.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_bal(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT sig; 7 | SPFLOAT comp; 8 | SPFLOAT out; 9 | sp_bal *bal; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "bal: Creating\n"); 16 | #endif 17 | 18 | sp_bal_create(&bal); 19 | plumber_add_ugen(pd, SPORTH_BAL, bal); 20 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for bal\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | sig = sporth_stack_pop_float(stack); 26 | comp = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "bal: Initialising\n"); 33 | #endif 34 | 35 | sig = sporth_stack_pop_float(stack); 36 | comp = sporth_stack_pop_float(stack); 37 | bal = pd->last->ud; 38 | sp_bal_init(pd->sp, bal); 39 | sporth_stack_push_float(stack, 0); 40 | break; 41 | case PLUMBER_COMPUTE: 42 | sig = sporth_stack_pop_float(stack); 43 | comp = sporth_stack_pop_float(stack); 44 | bal = pd->last->ud; 45 | sp_bal_compute(pd->sp, bal, &sig, &comp, &out); 46 | sporth_stack_push_float(stack, out); 47 | break; 48 | case PLUMBER_DESTROY: 49 | bal = pd->last->ud; 50 | sp_bal_destroy(&bal); 51 | break; 52 | default: 53 | plumber_print(pd, "bal: Unknown mode!\n"); 54 | break; 55 | } 56 | return PLUMBER_OK; 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/gen_sinesum.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "plumber.h" 5 | 6 | int sporth_gen_sinesum(sporth_stack *stack, void *ud) 7 | { 8 | plumber_data *pd = ud; 9 | 10 | int size; 11 | sp_ftbl *ft; 12 | const char *str; 13 | const char *args; 14 | 15 | switch(pd->mode){ 16 | case PLUMBER_CREATE: 17 | plumber_add_ugen(pd, SPORTH_GEN_SINESUM, NULL); 18 | if(sporth_check_args(stack, "sfs") != SPORTH_OK) { 19 | plumber_print(pd, "Init: not enough arguments for gen_sinesum\n"); 20 | return PLUMBER_NOTOK; 21 | } 22 | 23 | args = sporth_stack_pop_string(stack); 24 | size = (int)sporth_stack_pop_float(stack); 25 | str = sporth_stack_pop_string(stack); 26 | #ifdef DEBUG_MODE 27 | plumber_print(pd, "Creating sinesum table %s of size %d\n", str, size); 28 | #endif 29 | sp_ftbl_create(pd->sp, &ft, size); 30 | if(sp_gen_sinesum(pd->sp, ft, args) == SP_NOT_OK) { 31 | plumber_print(pd, "There was an issue creating the sinesume ftable \"%s\".\n", str); 32 | stack->error++; 33 | return PLUMBER_NOTOK; 34 | } 35 | plumber_ftmap_add(pd, str, ft); 36 | break; 37 | 38 | case PLUMBER_INIT: 39 | args = sporth_stack_pop_string(stack); 40 | size = (int)sporth_stack_pop_float(stack); 41 | str = sporth_stack_pop_string(stack); 42 | break; 43 | 44 | case PLUMBER_COMPUTE: 45 | size = (int)sporth_stack_pop_float(stack); 46 | break; 47 | 48 | case PLUMBER_DESTROY: 49 | break; 50 | 51 | default: 52 | printf("Error: Unknown mode!"); 53 | break; 54 | } 55 | return PLUMBER_OK; 56 | } 57 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/tone.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_tone(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT in; 7 | SPFLOAT out; 8 | SPFLOAT hp; 9 | sp_tone *tone; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "tone: Creating\n"); 16 | #endif 17 | sp_tone_create(&tone); 18 | plumber_add_ugen(pd, SPORTH_TONE, tone); 19 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 20 | plumber_print(pd,"Not enough arguments for tone\n"); 21 | stack->error++; 22 | return PLUMBER_NOTOK; 23 | } 24 | hp = sporth_stack_pop_float(stack); 25 | in = sporth_stack_pop_float(stack); 26 | sporth_stack_push_float(stack, 0); 27 | break; 28 | case PLUMBER_INIT: 29 | 30 | #ifdef DEBUG_MODE 31 | plumber_print(pd, "tone: Initialising\n"); 32 | #endif 33 | hp = sporth_stack_pop_float(stack); 34 | in = sporth_stack_pop_float(stack); 35 | tone = pd->last->ud; 36 | sp_tone_init(pd->sp, tone); 37 | sporth_stack_push_float(stack, 0); 38 | break; 39 | case PLUMBER_COMPUTE: 40 | hp = sporth_stack_pop_float(stack); 41 | in = sporth_stack_pop_float(stack); 42 | tone = pd->last->ud; 43 | tone->hp = hp; 44 | sp_tone_compute(pd->sp, tone, &in, &out); 45 | sporth_stack_push_float(stack, out); 46 | break; 47 | case PLUMBER_DESTROY: 48 | tone = pd->last->ud; 49 | sp_tone_destroy(&tone); 50 | break; 51 | default: 52 | plumber_print(pd, "tone: Unknown mode!\n"); 53 | break; 54 | } 55 | return PLUMBER_OK; 56 | } 57 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/clip.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_clip(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT in; 7 | SPFLOAT out; 8 | SPFLOAT lim; 9 | sp_clip *clip; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "clip: Creating\n"); 16 | #endif 17 | 18 | sp_clip_create(&clip); 19 | plumber_add_ugen(pd, SPORTH_CLIP, clip); 20 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for clip\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | lim = sporth_stack_pop_float(stack); 26 | in = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "clip: Initialising\n"); 33 | #endif 34 | lim = sporth_stack_pop_float(stack); 35 | in = sporth_stack_pop_float(stack); 36 | clip = pd->last->ud; 37 | sp_clip_init(pd->sp, clip); 38 | sporth_stack_push_float(stack, 0); 39 | break; 40 | case PLUMBER_COMPUTE: 41 | lim = sporth_stack_pop_float(stack); 42 | in = sporth_stack_pop_float(stack); 43 | clip = pd->last->ud; 44 | clip->lim = lim; 45 | sp_clip_compute(pd->sp, clip, &in, &out); 46 | sporth_stack_push_float(stack, out); 47 | break; 48 | case PLUMBER_DESTROY: 49 | clip = pd->last->ud; 50 | sp_clip_destroy(&clip); 51 | break; 52 | default: 53 | plumber_print(pd, "clip: Unknown mode!\n"); 54 | break; 55 | } 56 | return PLUMBER_OK; 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/switch.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_switch(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT trig; 7 | SPFLOAT input_1; 8 | SPFLOAT input_2; 9 | SPFLOAT out; 10 | sp_switch *sw; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "switch: creating\n"); 17 | #endif 18 | 19 | sp_switch_create(&sw); 20 | plumber_add_ugen(pd, SPORTH_SWITCH, sw); 21 | break; 22 | case PLUMBER_INIT: 23 | 24 | #ifdef DEBUG_MODE 25 | plumber_print(pd, "switch: initialising\n"); 26 | #endif 27 | 28 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 29 | plumber_print(pd,"Not enough arguments for switch\n"); 30 | stack->error++; 31 | return PLUMBER_NOTOK; 32 | } 33 | trig = sporth_stack_pop_float(stack); 34 | input_1 = sporth_stack_pop_float(stack); 35 | input_2 = sporth_stack_pop_float(stack); 36 | sw = pd->last->ud; 37 | sp_switch_init(pd->sp, sw); 38 | sporth_stack_push_float(stack, 0); 39 | break; 40 | case PLUMBER_COMPUTE: 41 | input_2 = sporth_stack_pop_float(stack); 42 | input_1 = sporth_stack_pop_float(stack); 43 | trig = sporth_stack_pop_float(stack); 44 | sw = pd->last->ud; 45 | sp_switch_compute(pd->sp, sw, &trig, &input_1, &input_2, &out); 46 | sporth_stack_push_float(stack, out); 47 | break; 48 | case PLUMBER_DESTROY: 49 | sw = pd->last->ud; 50 | sp_switch_destroy(&sw); 51 | break; 52 | default: 53 | plumber_print(pd, "switch: unknown mode!\n"); 54 | break; 55 | } 56 | return PLUMBER_OK; 57 | } 58 | -------------------------------------------------------------------------------- /Demo/Shared/Operations/PhasorOperation.swift: -------------------------------------------------------------------------------- 1 | import AudioKit 2 | import AudioKitUI 3 | import SporthAudioKit 4 | import SwiftUI 5 | 6 | class PhasorOperationConductor: ObservableObject, HasAudioEngine { 7 | let engine = AudioEngine() 8 | 9 | @Published var isRunning = false { 10 | didSet { 11 | isRunning ? generator.start() : generator.stop() 12 | } 13 | } 14 | 15 | let generator = OperationGenerator { 16 | let interval: Double = 2 17 | let noteCount: Double = 24 18 | let startingNote: Double = 48 // C 19 | 20 | let phasing = Operation.phasor(frequency: 0.5) * Operation.randomNumberPulse(minimum: 0.9, maximum: 2, updateFrequency: 0.5) 21 | let frequency = (floor(phasing * noteCount) * interval + startingNote) 22 | .midiNoteToFrequency() 23 | 24 | var amplitude = (phasing - 1).portamento() // prevents the click sound 25 | 26 | var oscillator = Operation.sineWave(frequency: frequency, amplitude: amplitude) 27 | let reverb = oscillator.reverberateWithChowning() 28 | return mixer(oscillator, reverb, balance: 0.6) 29 | } 30 | 31 | init() { 32 | engine.output = generator 33 | } 34 | } 35 | 36 | struct PhasorOperationView: View { 37 | @StateObject var conductor = PhasorOperationConductor() 38 | 39 | var body: some View { 40 | VStack(spacing: 50) { 41 | Text("Using the phasor to sweep amplitude and frequencies") 42 | Text(conductor.isRunning ? "Stop" : "Start").onTapGesture { 43 | conductor.isRunning.toggle() 44 | } 45 | NodeOutputView(conductor.generator) 46 | } 47 | .padding() 48 | .navigationTitle("Phasor Operation") 49 | .onAppear { 50 | conductor.start() 51 | } 52 | .onDisappear { 53 | conductor.stop() 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/atone.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_atone(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT in; 7 | SPFLOAT out; 8 | SPFLOAT hp; 9 | sp_atone *atone; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "atone: Creating\n"); 16 | #endif 17 | 18 | sp_atone_create(&atone); 19 | plumber_add_ugen(pd, SPORTH_ATONE, atone); 20 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for atone\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | hp = sporth_stack_pop_float(stack); 26 | in = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "atone: Initialising\n"); 33 | #endif 34 | hp = sporth_stack_pop_float(stack); 35 | in = sporth_stack_pop_float(stack); 36 | atone = pd->last->ud; 37 | sp_atone_init(pd->sp, atone); 38 | sporth_stack_push_float(stack, 0); 39 | break; 40 | case PLUMBER_COMPUTE: 41 | hp = sporth_stack_pop_float(stack); 42 | in = sporth_stack_pop_float(stack); 43 | atone = pd->last->ud; 44 | atone->hp = hp; 45 | sp_atone_compute(pd->sp, atone, &in, &out); 46 | sporth_stack_push_float(stack, out); 47 | break; 48 | case PLUMBER_DESTROY: 49 | atone = pd->last->ud; 50 | sp_atone_destroy(&atone); 51 | break; 52 | default: 53 | plumber_print(pd, "atone: Unknown mode!\n"); 54 | break; 55 | } 56 | return PLUMBER_OK; 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/sdelay.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_sdelay(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT out; 8 | SPFLOAT size; 9 | sp_sdelay *sdelay; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "sdelay: Creating\n"); 16 | #endif 17 | 18 | sp_sdelay_create(&sdelay); 19 | plumber_add_ugen(pd, SPORTH_SDELAY, sdelay); 20 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for sdelay\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | size = sporth_stack_pop_float(stack); 26 | input = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "sdelay: Initialising\n"); 33 | #endif 34 | 35 | size = sporth_stack_pop_float(stack); 36 | input = sporth_stack_pop_float(stack); 37 | sdelay = pd->last->ud; 38 | sp_sdelay_init(pd->sp, sdelay, size); 39 | sporth_stack_push_float(stack, 0); 40 | break; 41 | case PLUMBER_COMPUTE: 42 | size = sporth_stack_pop_float(stack); 43 | input = sporth_stack_pop_float(stack); 44 | sdelay = pd->last->ud; 45 | sp_sdelay_compute(pd->sp, sdelay, &input, &out); 46 | sporth_stack_push_float(stack, out); 47 | break; 48 | case PLUMBER_DESTROY: 49 | sdelay = pd->last->ud; 50 | sp_sdelay_destroy(&sdelay); 51 | break; 52 | default: 53 | plumber_print(pd, "sdelay: Unknown mode!\n"); 54 | break; 55 | } 56 | return PLUMBER_OK; 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/gen_line.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "plumber.h" 5 | 6 | int sporth_gen_line(sporth_stack *stack, void *ud) 7 | { 8 | plumber_data *pd = ud; 9 | 10 | int size; 11 | sp_ftbl *ft; 12 | const char *str; 13 | const char *args; 14 | 15 | switch(pd->mode){ 16 | case PLUMBER_CREATE: 17 | #ifdef DEBUG_MODE 18 | plumber_print(pd, "gen_line: create mode\n"); 19 | #endif 20 | plumber_add_ugen(pd, SPORTH_GEN_LINE, NULL); 21 | if(sporth_check_args(stack, "sfs") != SPORTH_OK) { 22 | plumber_print(pd, "Init: not enough arguments for gen_line\n"); 23 | return PLUMBER_NOTOK; 24 | } 25 | args = sporth_stack_pop_string(stack); 26 | size = (int)sporth_stack_pop_float(stack); 27 | str = sporth_stack_pop_string(stack); 28 | #ifdef DEBUG_MODE 29 | plumber_print(pd, "Creating line table %s of size %d\n", str, size); 30 | #endif 31 | sp_ftbl_create(pd->sp, &ft, size); 32 | if(sp_gen_line(pd->sp, ft, args) == SP_NOT_OK) { 33 | plumber_print(pd, "There was an issue creating the line ftable \"%s\".\n", str); 34 | stack->error++; 35 | return PLUMBER_NOTOK; 36 | } 37 | plumber_ftmap_add(pd, str, ft); 38 | break; 39 | 40 | case PLUMBER_INIT: 41 | 42 | args = sporth_stack_pop_string(stack); 43 | size = (int)sporth_stack_pop_float(stack); 44 | str = sporth_stack_pop_string(stack); 45 | break; 46 | 47 | case PLUMBER_COMPUTE: 48 | sporth_stack_pop_float(stack); 49 | break; 50 | 51 | case PLUMBER_DESTROY: 52 | break; 53 | 54 | default: 55 | printf("Error: Unknown mode!"); 56 | break; 57 | } 58 | return PLUMBER_OK; 59 | } 60 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/buthp.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_buthp(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT output; 8 | SPFLOAT freq; 9 | sp_buthp *buthp; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "buthp: Creating\n"); 16 | #endif 17 | 18 | sp_buthp_create(&buthp); 19 | plumber_add_ugen(pd, SPORTH_BUTHP, buthp); 20 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for buthp\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | freq = sporth_stack_pop_float(stack); 26 | input = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "buthp: Initialising\n"); 33 | #endif 34 | freq = sporth_stack_pop_float(stack); 35 | input = sporth_stack_pop_float(stack); 36 | buthp = pd->last->ud; 37 | sp_buthp_init(pd->sp, buthp); 38 | sporth_stack_push_float(stack, 0); 39 | break; 40 | case PLUMBER_COMPUTE: 41 | freq = sporth_stack_pop_float(stack); 42 | input = sporth_stack_pop_float(stack); 43 | buthp = pd->last->ud; 44 | buthp->freq = freq; 45 | sp_buthp_compute(pd->sp, buthp, &input, &output); 46 | sporth_stack_push_float(stack, output); 47 | break; 48 | case PLUMBER_DESTROY: 49 | buthp = pd->last->ud; 50 | sp_buthp_destroy(&buthp); 51 | break; 52 | default: 53 | plumber_print(pd, "buthp: Unknown mode!\n"); 54 | break; 55 | } 56 | return PLUMBER_OK; 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/butlp.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_butlp(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT output; 8 | SPFLOAT freq; 9 | sp_butlp *butlp; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "butlp: Creating\n"); 16 | #endif 17 | 18 | sp_butlp_create(&butlp); 19 | plumber_add_ugen(pd, SPORTH_BUTLP, butlp); 20 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for butlp\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | freq = sporth_stack_pop_float(stack); 26 | input = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "butlp: Initialising\n"); 33 | #endif 34 | freq = sporth_stack_pop_float(stack); 35 | input = sporth_stack_pop_float(stack); 36 | butlp = pd->last->ud; 37 | sp_butlp_init(pd->sp, butlp); 38 | sporth_stack_push_float(stack, 0); 39 | break; 40 | case PLUMBER_COMPUTE: 41 | freq = sporth_stack_pop_float(stack); 42 | input = sporth_stack_pop_float(stack); 43 | butlp = pd->last->ud; 44 | butlp->freq = freq; 45 | sp_butlp_compute(pd->sp, butlp, &input, &output); 46 | sporth_stack_push_float(stack, output); 47 | break; 48 | case PLUMBER_DESTROY: 49 | butlp = pd->last->ud; 50 | sp_butlp_destroy(&butlp); 51 | break; 52 | default: 53 | plumber_print(pd, "butlp: Unknown mode!\n"); 54 | break; 55 | } 56 | return PLUMBER_OK; 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/delay.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_delay(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT out; 8 | SPFLOAT time; 9 | SPFLOAT feedback; 10 | sp_delay *delay; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "delay: Creating\n"); 17 | #endif 18 | 19 | sp_delay_create(&delay); 20 | plumber_add_ugen(pd, SPORTH_DELAY, delay); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for delay\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | time = sporth_stack_pop_float(stack); 27 | feedback = sporth_stack_pop_float(stack); 28 | input = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | time = sporth_stack_pop_float(stack); 33 | feedback = sporth_stack_pop_float(stack); 34 | input = sporth_stack_pop_float(stack); 35 | delay = pd->last->ud; 36 | sp_delay_init(pd->sp, delay, time); 37 | sporth_stack_push_float(stack, 0); 38 | break; 39 | case PLUMBER_COMPUTE: 40 | time = sporth_stack_pop_float(stack); 41 | feedback = sporth_stack_pop_float(stack); 42 | input = sporth_stack_pop_float(stack); 43 | delay = pd->last->ud; 44 | delay->feedback = feedback; 45 | sp_delay_compute(pd->sp, delay, &input, &out); 46 | sporth_stack_push_float(stack, out); 47 | break; 48 | case PLUMBER_DESTROY: 49 | delay = pd->last->ud; 50 | sp_delay_destroy(&delay); 51 | break; 52 | } 53 | return PLUMBER_OK; 54 | } 55 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/hilbert.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_hilbert(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT out1; 8 | SPFLOAT out2; 9 | sp_hilbert *hilbert; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "hilbert: Creating\n"); 16 | #endif 17 | 18 | sp_hilbert_create(&hilbert); 19 | plumber_add_ugen(pd, SPORTH_HILBERT, hilbert); 20 | if(sporth_check_args(stack, "f") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for hilbert\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | input = sporth_stack_pop_float(stack); 26 | sporth_stack_push_float(stack, 0); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "hilbert: Initialising\n"); 33 | #endif 34 | 35 | input = sporth_stack_pop_float(stack); 36 | hilbert = pd->last->ud; 37 | sp_hilbert_init(pd->sp, hilbert); 38 | sporth_stack_push_float(stack, 0); 39 | sporth_stack_push_float(stack, 0); 40 | break; 41 | case PLUMBER_COMPUTE: 42 | input = sporth_stack_pop_float(stack); 43 | hilbert = pd->last->ud; 44 | sp_hilbert_compute(pd->sp, hilbert, &input, &out1, &out2); 45 | sporth_stack_push_float(stack, out1); 46 | sporth_stack_push_float(stack, out2); 47 | break; 48 | case PLUMBER_DESTROY: 49 | hilbert = pd->last->ud; 50 | sp_hilbert_destroy(&hilbert); 51 | break; 52 | default: 53 | plumber_print(pd, "hilbert: Unknown mode!\n"); 54 | break; 55 | } 56 | return PLUMBER_OK; 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/reverse.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_reverse(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT out; 8 | SPFLOAT delay; 9 | sp_reverse *reverse; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "reverse: Creating\n"); 16 | #endif 17 | 18 | sp_reverse_create(&reverse); 19 | plumber_add_ugen(pd, SPORTH_REVERSE, reverse); 20 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for reverse\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | delay = sporth_stack_pop_float(stack); 26 | input = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "reverse: Initialising\n"); 33 | #endif 34 | delay = sporth_stack_pop_float(stack); 35 | input = sporth_stack_pop_float(stack); 36 | reverse = pd->last->ud; 37 | sp_reverse_init(pd->sp, reverse, delay); 38 | sporth_stack_push_float(stack, 0); 39 | break; 40 | case PLUMBER_COMPUTE: 41 | delay = sporth_stack_pop_float(stack); 42 | input = sporth_stack_pop_float(stack); 43 | reverse = pd->last->ud; 44 | sp_reverse_compute(pd->sp, reverse, &input, &out); 45 | sporth_stack_push_float(stack, out); 46 | break; 47 | case PLUMBER_DESTROY: 48 | reverse = pd->last->ud; 49 | sp_reverse_destroy(&reverse); 50 | break; 51 | default: 52 | plumber_print(pd, "reverse: Unknown mode!\n"); 53 | break; 54 | } 55 | return PLUMBER_OK; 56 | } 57 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/phasor.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_phasor(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT out; 7 | SPFLOAT iphs; 8 | SPFLOAT freq; 9 | sp_phasor *phasor; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "phasor: Creating\n"); 16 | #endif 17 | 18 | sp_phasor_create(&phasor); 19 | plumber_add_ugen(pd, SPORTH_PHASOR, phasor); 20 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for phasor\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | iphs = sporth_stack_pop_float(stack); 26 | freq = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "phasor: Initialising\n"); 33 | #endif 34 | iphs = sporth_stack_pop_float(stack); 35 | freq = sporth_stack_pop_float(stack); 36 | phasor = pd->last->ud; 37 | sp_phasor_init(pd->sp, phasor, iphs); 38 | sporth_stack_push_float(stack, 0); 39 | break; 40 | case PLUMBER_COMPUTE: 41 | iphs = sporth_stack_pop_float(stack); 42 | freq = sporth_stack_pop_float(stack); 43 | phasor = pd->last->ud; 44 | phasor->freq = freq; 45 | sp_phasor_compute(pd->sp, phasor, NULL, &out); 46 | sporth_stack_push_float(stack, out); 47 | break; 48 | case PLUMBER_DESTROY: 49 | phasor = pd->last->ud; 50 | sp_phasor_destroy(&phasor); 51 | break; 52 | default: 53 | plumber_print(pd, "phasor: Unknown mode!\n"); 54 | break; 55 | } 56 | return PLUMBER_OK; 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/tgate.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_tgate(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT trigger; 7 | SPFLOAT gate; 8 | SPFLOAT time; 9 | sp_tgate *tgate; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "tgate: Creating\n"); 16 | #endif 17 | 18 | sp_tgate_create(&tgate); 19 | plumber_add_ugen(pd, SPORTH_TGATE, tgate); 20 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for tgate\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | time = sporth_stack_pop_float(stack); 26 | trigger = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "tgate: Initialising\n"); 33 | #endif 34 | 35 | time = sporth_stack_pop_float(stack); 36 | trigger = sporth_stack_pop_float(stack); 37 | tgate = pd->last->ud; 38 | sp_tgate_init(pd->sp, tgate); 39 | sporth_stack_push_float(stack, 0); 40 | break; 41 | case PLUMBER_COMPUTE: 42 | time = sporth_stack_pop_float(stack); 43 | trigger = sporth_stack_pop_float(stack); 44 | tgate = pd->last->ud; 45 | tgate->time = time; 46 | sp_tgate_compute(pd->sp, tgate, &trigger, &gate); 47 | sporth_stack_push_float(stack, gate); 48 | break; 49 | case PLUMBER_DESTROY: 50 | tgate = pd->last->ud; 51 | sp_tgate_destroy(&tgate); 52 | break; 53 | default: 54 | plumber_print(pd, "tgate: Unknown mode!\n"); 55 | break; 56 | } 57 | return PLUMBER_OK; 58 | } 59 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/blsaw.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_blsaw(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT out; 7 | SPFLOAT freq; 8 | SPFLOAT amp; 9 | sp_blsaw *blsaw; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "blsaw: Creating\n"); 16 | #endif 17 | 18 | sp_blsaw_create(&blsaw); 19 | plumber_add_ugen(pd, SPORTH_SAW, blsaw); 20 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for blsaw\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | amp = sporth_stack_pop_float(stack); 26 | freq = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "blsaw: Initialising\n"); 33 | #endif 34 | amp = sporth_stack_pop_float(stack); 35 | freq = sporth_stack_pop_float(stack); 36 | blsaw = pd->last->ud; 37 | sp_blsaw_init(pd->sp, blsaw); 38 | sporth_stack_push_float(stack, 0); 39 | break; 40 | case PLUMBER_COMPUTE: 41 | amp = sporth_stack_pop_float(stack); 42 | freq = sporth_stack_pop_float(stack); 43 | blsaw = pd->last->ud; 44 | *blsaw->freq = freq; 45 | *blsaw->amp = amp; 46 | sp_blsaw_compute(pd->sp, blsaw, NULL, &out); 47 | sporth_stack_push_float(stack, out); 48 | break; 49 | case PLUMBER_DESTROY: 50 | blsaw = pd->last->ud; 51 | sp_blsaw_destroy(&blsaw); 52 | break; 53 | default: 54 | plumber_print(pd, "blsaw: Unknown mode!\n"); 55 | break; 56 | } 57 | return PLUMBER_OK; 58 | } 59 | -------------------------------------------------------------------------------- /Demo/Shared/Operations/VocalTractOperation.swift: -------------------------------------------------------------------------------- 1 | import AudioKit 2 | import AudioKitUI 3 | import AudioToolbox 4 | import SporthAudioKit 5 | import SwiftUI 6 | 7 | class VocalTractOperationConductor: ObservableObject, HasAudioEngine { 8 | @Published var isPlaying = false { 9 | didSet { 10 | isPlaying ? generator.start() : generator.stop() 11 | } 12 | } 13 | 14 | let engine = AudioEngine() 15 | 16 | let generator = OperationGenerator { 17 | let frequency = Operation.sineWave(frequency: 1).scale(minimum: 100, maximum: 300) 18 | let jitter = Operation.jitter(amplitude: 300, minimumFrequency: 1, maximumFrequency: 3) 19 | let position = Operation.sineWave(frequency: 0.1).scale() 20 | let diameter = Operation.sineWave(frequency: 0.2).scale() 21 | let tenseness = Operation.sineWave(frequency: 0.3).scale() 22 | let nasality = Operation.sineWave(frequency: 0.35).scale() 23 | return Operation.vocalTract(frequency: frequency + jitter, 24 | tonguePosition: position, 25 | tongueDiameter: diameter, 26 | tenseness: tenseness, 27 | nasality: nasality) 28 | } 29 | 30 | init() { 31 | engine.output = generator 32 | } 33 | } 34 | 35 | struct VocalTractOperationView: View { 36 | @StateObject var conductor = VocalTractOperationConductor() 37 | 38 | var body: some View { 39 | VStack(spacing: 50) { 40 | Text(conductor.isPlaying ? "Stop!" : "More!").onTapGesture { 41 | conductor.isPlaying.toggle() 42 | } 43 | NodeOutputView(conductor.generator) 44 | } 45 | .navigationTitle("Vocal Fun") 46 | .padding() 47 | .onAppear { 48 | conductor.start() 49 | } 50 | .onDisappear { 51 | conductor.stop() 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/pdhalf.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_pdhalf(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT sig; 7 | SPFLOAT out; 8 | SPFLOAT amount; 9 | sp_pdhalf *pdhalf; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "pdhalf: Creating\n"); 16 | #endif 17 | 18 | sp_pdhalf_create(&pdhalf); 19 | plumber_add_ugen(pd, SPORTH_PDHALF, pdhalf); 20 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for pdhalf\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | amount = sporth_stack_pop_float(stack); 26 | sig = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "pdhalf: Initialising\n"); 33 | #endif 34 | 35 | amount = sporth_stack_pop_float(stack); 36 | sig = sporth_stack_pop_float(stack); 37 | pdhalf = pd->last->ud; 38 | sp_pdhalf_init(pd->sp, pdhalf); 39 | sporth_stack_push_float(stack, 0); 40 | break; 41 | case PLUMBER_COMPUTE: 42 | amount = sporth_stack_pop_float(stack); 43 | sig = sporth_stack_pop_float(stack); 44 | pdhalf = pd->last->ud; 45 | pdhalf->amount = amount; 46 | sp_pdhalf_compute(pd->sp, pdhalf, &sig, &out); 47 | sporth_stack_push_float(stack, out); 48 | break; 49 | case PLUMBER_DESTROY: 50 | pdhalf = pd->last->ud; 51 | sp_pdhalf_destroy(&pdhalf); 52 | break; 53 | default: 54 | plumber_print(pd, "pdhalf: Unknown mode!\n"); 55 | break; 56 | } 57 | return PLUMBER_OK; 58 | } 59 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/samphold.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_samphold(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT trig; 7 | SPFLOAT input; 8 | SPFLOAT out; 9 | sp_samphold *samphold; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "samphold: Creating\n"); 16 | #endif 17 | 18 | sp_samphold_create(&samphold); 19 | plumber_add_ugen(pd, SPORTH_SAMPHOLD, samphold); 20 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for samphold\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | trig = sporth_stack_pop_float(stack); 26 | input = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, input); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "samphold: Initialising\n"); 33 | #endif 34 | 35 | trig = sporth_stack_pop_float(stack); 36 | input = sporth_stack_pop_float(stack); 37 | samphold = pd->last->ud; 38 | sp_samphold_init(pd->sp, samphold); 39 | sporth_stack_push_float(stack, input); 40 | break; 41 | case PLUMBER_COMPUTE: 42 | trig = sporth_stack_pop_float(stack); 43 | input = sporth_stack_pop_float(stack); 44 | samphold = pd->last->ud; 45 | sp_samphold_compute(pd->sp, samphold, &trig, &input, &out); 46 | sporth_stack_push_float(stack, out); 47 | break; 48 | case PLUMBER_DESTROY: 49 | samphold = pd->last->ud; 50 | sp_samphold_destroy(&samphold); 51 | break; 52 | default: 53 | plumber_print(pd, "samphold: Unknown mode!\n"); 54 | break; 55 | } 56 | return PLUMBER_OK; 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/butbp.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_butbp(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT output; 8 | SPFLOAT freq; 9 | SPFLOAT bw; 10 | sp_butbp *butbp; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "butbp: Creating\n"); 17 | #endif 18 | 19 | sp_butbp_create(&butbp); 20 | plumber_add_ugen(pd, SPORTH_BUTBP, butbp); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for butbp\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | sporth_stack_push_float(stack, 0); 27 | break; 28 | case PLUMBER_INIT: 29 | 30 | #ifdef DEBUG_MODE 31 | plumber_print(pd, "butbp: Initialising\n"); 32 | #endif 33 | 34 | bw = sporth_stack_pop_float(stack); 35 | freq = sporth_stack_pop_float(stack); 36 | input = sporth_stack_pop_float(stack); 37 | butbp = pd->last->ud; 38 | sp_butbp_init(pd->sp, butbp); 39 | sporth_stack_push_float(stack, 0); 40 | break; 41 | case PLUMBER_COMPUTE: 42 | bw = sporth_stack_pop_float(stack); 43 | freq = sporth_stack_pop_float(stack); 44 | input = sporth_stack_pop_float(stack); 45 | butbp = pd->last->ud; 46 | butbp->freq = freq; 47 | butbp->bw = bw; 48 | sp_butbp_compute(pd->sp, butbp, &input, &output); 49 | sporth_stack_push_float(stack, output); 50 | break; 51 | case PLUMBER_DESTROY: 52 | butbp = pd->last->ud; 53 | sp_butbp_destroy(&butbp); 54 | break; 55 | default: 56 | plumber_print(pd, "butbp: Unknown mode!\n"); 57 | break; 58 | } 59 | return PLUMBER_OK; 60 | } 61 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/butbr.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_butbr(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT output; 8 | SPFLOAT freq; 9 | SPFLOAT bw; 10 | sp_butbr *butbr; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "butbr: Creating\n"); 17 | #endif 18 | 19 | sp_butbr_create(&butbr); 20 | plumber_add_ugen(pd, SPORTH_BUTBR, butbr); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for butbr\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | sporth_stack_push_float(stack, 0); 27 | break; 28 | case PLUMBER_INIT: 29 | 30 | #ifdef DEBUG_MODE 31 | plumber_print(pd, "butbr: Initialising\n"); 32 | #endif 33 | 34 | bw = sporth_stack_pop_float(stack); 35 | freq = sporth_stack_pop_float(stack); 36 | input = sporth_stack_pop_float(stack); 37 | butbr = pd->last->ud; 38 | sp_butbr_init(pd->sp, butbr); 39 | sporth_stack_push_float(stack, 0); 40 | break; 41 | case PLUMBER_COMPUTE: 42 | bw = sporth_stack_pop_float(stack); 43 | freq = sporth_stack_pop_float(stack); 44 | input = sporth_stack_pop_float(stack); 45 | butbr = pd->last->ud; 46 | butbr->freq = freq; 47 | butbr->bw = bw; 48 | sp_butbr_compute(pd->sp, butbr, &input, &output); 49 | sporth_stack_push_float(stack, output); 50 | break; 51 | case PLUMBER_DESTROY: 52 | butbr = pd->last->ud; 53 | sp_butbr_destroy(&butbr); 54 | break; 55 | default: 56 | plumber_print(pd, "butbr: Unknown mode!\n"); 57 | break; 58 | } 59 | return PLUMBER_OK; 60 | } 61 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/maygate.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_maygate(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT trig; 7 | SPFLOAT out; 8 | SPFLOAT prob; 9 | sp_maygate *maygate; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "maygate: Creating\n"); 16 | #endif 17 | 18 | sp_maygate_create(&maygate); 19 | plumber_add_ugen(pd, SPORTH_MAYGATE, maygate); 20 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for maygate\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | prob = sporth_stack_pop_float(stack); 26 | trig = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "maygate: Initialising\n"); 33 | #endif 34 | 35 | prob = sporth_stack_pop_float(stack); 36 | trig = sporth_stack_pop_float(stack); 37 | maygate = pd->last->ud; 38 | sp_maygate_init(pd->sp, maygate); 39 | maygate->mode = 0; 40 | sporth_stack_push_float(stack, 0); 41 | break; 42 | case PLUMBER_COMPUTE: 43 | prob = sporth_stack_pop_float(stack); 44 | trig = sporth_stack_pop_float(stack); 45 | maygate = pd->last->ud; 46 | maygate->prob = prob; 47 | sp_maygate_compute(pd->sp, maygate, &trig, &out); 48 | sporth_stack_push_float(stack, out); 49 | break; 50 | case PLUMBER_DESTROY: 51 | maygate = pd->last->ud; 52 | sp_maygate_destroy(&maygate); 53 | break; 54 | default: 55 | plumber_print(pd, "maygate: Unknown mode!\n"); 56 | break; 57 | } 58 | return PLUMBER_OK; 59 | } 60 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/dust.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_dust(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT out; 7 | SPFLOAT amp; 8 | SPFLOAT density; 9 | int bipolar; 10 | sp_dust *dust; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "dust: Creating\n"); 17 | #endif 18 | 19 | sp_dust_create(&dust); 20 | plumber_add_ugen(pd, SPORTH_DUST, dust); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for dust\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | sporth_stack_push_float(stack, 0); 27 | break; 28 | case PLUMBER_INIT: 29 | 30 | #ifdef DEBUG_MODE 31 | plumber_print(pd, "dust: Initialising\n"); 32 | #endif 33 | 34 | bipolar = (int)sporth_stack_pop_float(stack); 35 | density = sporth_stack_pop_float(stack); 36 | amp = sporth_stack_pop_float(stack); 37 | dust = pd->last->ud; 38 | sp_dust_init(pd->sp, dust); 39 | sporth_stack_push_float(stack, 0); 40 | break; 41 | case PLUMBER_COMPUTE: 42 | bipolar = (int)sporth_stack_pop_float(stack); 43 | density = sporth_stack_pop_float(stack); 44 | amp = sporth_stack_pop_float(stack); 45 | dust = pd->last->ud; 46 | dust->amp = amp; 47 | dust->density = density; 48 | dust->bipolar = bipolar; 49 | sp_dust_compute(pd->sp, dust, NULL, &out); 50 | sporth_stack_push_float(stack, out); 51 | break; 52 | case PLUMBER_DESTROY: 53 | dust = pd->last->ud; 54 | sp_dust_destroy(&dust); 55 | break; 56 | default: 57 | plumber_print(pd, "dust: Unknown mode!\n"); 58 | break; 59 | } 60 | return PLUMBER_OK; 61 | } 62 | -------------------------------------------------------------------------------- /Demo/Shared/Operations/LFOOperation.swift: -------------------------------------------------------------------------------- 1 | import AudioKit 2 | import AudioKitUI 3 | import SporthAudioKit 4 | import SwiftUI 5 | 6 | class LFOOperationConductor: ObservableObject, HasAudioEngine { 7 | let engine = AudioEngine() 8 | 9 | @Published var isRunning = false { 10 | didSet { 11 | isRunning ? generator.start() : generator.stop() 12 | } 13 | } 14 | 15 | let generator = OperationGenerator { 16 | let frequencyLFO = Operation.square(frequency: 1) 17 | .scale(minimum: 440, maximum: 880) 18 | let carrierLFO = Operation.triangle(frequency: 1) 19 | .scale(minimum: 1, maximum: 2) 20 | let modulatingMultiplierLFO = Operation.sawtooth(frequency: 1) 21 | .scale(minimum: 0.1, maximum: 2) 22 | let modulatingIndexLFO = Operation.reverseSawtooth(frequency: 1) 23 | .scale(minimum: 0.1, maximum: 20) 24 | 25 | return Operation.fmOscillator( 26 | baseFrequency: frequencyLFO, 27 | carrierMultiplier: carrierLFO, 28 | modulatingMultiplier: modulatingMultiplierLFO, 29 | modulationIndex: modulatingIndexLFO, 30 | amplitude: 0.2 31 | ) 32 | } 33 | 34 | init() { 35 | engine.output = generator 36 | } 37 | } 38 | 39 | struct LFOOperationView: View { 40 | @StateObject var conductor = LFOOperationConductor() 41 | 42 | var body: some View { 43 | VStack(spacing: 50) { 44 | Text("Often we want rhythmic changing of parameters that varying in a standard way. This is traditionally done with Low-Frequency Oscillators, LFOs.") 45 | Text(conductor.isRunning ? "Stop" : "Start").onTapGesture { 46 | conductor.isRunning.toggle() 47 | } 48 | NodeOutputView(conductor.generator) 49 | } 50 | .padding() 51 | .navigationTitle("LFO Operation") 52 | .onAppear { 53 | conductor.start() 54 | } 55 | .onDisappear { 56 | conductor.stop() 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/maytrig.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_maytrig(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT trig; 7 | SPFLOAT out; 8 | SPFLOAT prob; 9 | sp_maygate *maygate; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "maytrig: Creating\n"); 16 | #endif 17 | 18 | sp_maygate_create(&maygate); 19 | plumber_add_ugen(pd, SPORTH_MAYTRIG, maygate); 20 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for maygate\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | prob = sporth_stack_pop_float(stack); 26 | trig = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "maytrig: Initialising\n"); 33 | #endif 34 | 35 | prob = sporth_stack_pop_float(stack); 36 | trig = sporth_stack_pop_float(stack); 37 | maygate = pd->last->ud; 38 | sp_maygate_init(pd->sp, maygate); 39 | /* this line makes things a maytrig */ 40 | maygate->mode = 1; 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | prob = sporth_stack_pop_float(stack); 45 | trig = sporth_stack_pop_float(stack); 46 | maygate = pd->last->ud; 47 | maygate->prob = prob; 48 | sp_maygate_compute(pd->sp, maygate, &trig, &out); 49 | sporth_stack_push_float(stack, out); 50 | break; 51 | case PLUMBER_DESTROY: 52 | maygate = pd->last->ud; 53 | sp_maygate_destroy(&maygate); 54 | break; 55 | default: 56 | plumber_print(pd, "maygate: Unknown mode!\n"); 57 | break; 58 | } 59 | return PLUMBER_OK; 60 | } 61 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/bltriangle.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_bltriangle(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT out; 7 | SPFLOAT freq; 8 | SPFLOAT amp; 9 | sp_bltriangle *bltriangle; 10 | 11 | switch(pd->mode) { 12 | case PLUMBER_CREATE: 13 | 14 | #ifdef DEBUG_MODE 15 | plumber_print(pd, "bltriangle: Creating\n"); 16 | #endif 17 | 18 | sp_bltriangle_create(&bltriangle); 19 | plumber_add_ugen(pd, SPORTH_TRIANGLE, bltriangle); 20 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 21 | plumber_print(pd,"Not enough arguments for bltriangle\n"); 22 | stack->error++; 23 | return PLUMBER_NOTOK; 24 | } 25 | amp = sporth_stack_pop_float(stack); 26 | freq = sporth_stack_pop_float(stack); 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "bltriangle: Initialising\n"); 33 | #endif 34 | amp = sporth_stack_pop_float(stack); 35 | freq = sporth_stack_pop_float(stack); 36 | bltriangle = pd->last->ud; 37 | sp_bltriangle_init(pd->sp, bltriangle); 38 | sporth_stack_push_float(stack, 0); 39 | break; 40 | case PLUMBER_COMPUTE: 41 | amp = sporth_stack_pop_float(stack); 42 | freq = sporth_stack_pop_float(stack); 43 | bltriangle = pd->last->ud; 44 | *bltriangle->freq = freq; 45 | *bltriangle->amp = amp; 46 | sp_bltriangle_compute(pd->sp, bltriangle, NULL, &out); 47 | sporth_stack_push_float(stack, out); 48 | break; 49 | case PLUMBER_DESTROY: 50 | bltriangle = pd->last->ud; 51 | sp_bltriangle_destroy(&bltriangle); 52 | break; 53 | default: 54 | plumber_print(pd, "bltriangle: Unknown mode!\n"); 55 | break; 56 | } 57 | return PLUMBER_OK; 58 | } 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | # Sporth AudioKit (AudioKit Operations) 5 | 6 | [![Build Status](https://github.com/AudioKit/SporthAudioKit/workflows/CI/badge.svg)](https://github.com/AudioKit/SporthAudioKit/actions?query=workflow%3ACI) 7 | [![License](https://img.shields.io/github/license/AudioKit/SporthAudioKit)](https://github.com/AudioKit/SporthAudioKit/blob/main/LICENSE) 8 | [![Swift Compatibility](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FAudioKit%2FSporthAudioKit%2Fbadge%3Ftype%3Dswift-versions&label=)](https://swiftpackageindex.com/AudioKit/SporthAudioKit) 9 | [![Platform Compatibility](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FAudioKit%2FSporthAudioKit%2Fbadge%3Ftype%3Dplatforms&label=)](https://swiftpackageindex.com/AudioKit/SporthAudioKit) 10 | [![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com) 11 | [![Twitter Follow](https://img.shields.io/twitter/follow/AudioKitPro.svg?style=social)](https://twitter.com/AudioKitPro) 12 | 13 |
14 | 15 | This extension to AudioKit allows for complex, interconnected DSP. 16 | 17 | ## Installation 18 | 19 | Install using the Swift Package Manager. 20 | 21 | ## Targets 22 | 23 | | Name | Description | Language | 24 | |-----------------|---------------------------------------------|---------------| 25 | | SporthAudioKit | API for creating Sporth-powered Audio Units | Swift | 26 | | CSporthAudioKit | Audio Unit for Operation DSP | Objective-C++ | 27 | | Sporth | Stack-based DSP language | C | 28 | 29 | ## Documentation 30 | 31 | The [AudioKit.io website](https://audiokit.io/SporthAudioKit/) hosts the documentation for this project. 32 | 33 | ## Examples 34 | 35 | See the [AudioKit Cookbook](https://github.com/AudioKit/Cookbook/) for complete examples. 36 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/line.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_line(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT trig; 7 | SPFLOAT out; 8 | SPFLOAT a; 9 | SPFLOAT dur; 10 | SPFLOAT b; 11 | sp_line *line; 12 | 13 | switch(pd->mode) { 14 | case PLUMBER_CREATE: 15 | 16 | #ifdef DEBUG_MODE 17 | plumber_print(pd, "line: Creating\n"); 18 | #endif 19 | 20 | sp_line_create(&line); 21 | plumber_add_ugen(pd, SPORTH_LINE, line); 22 | if(sporth_check_args(stack, "ffff") != SPORTH_OK) { 23 | plumber_print(pd,"Not enough arguments for line\n"); 24 | stack->error++; 25 | return PLUMBER_NOTOK; 26 | } 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "line: Initialising\n"); 33 | #endif 34 | 35 | b = sporth_stack_pop_float(stack); 36 | dur = sporth_stack_pop_float(stack); 37 | a = sporth_stack_pop_float(stack); 38 | trig = sporth_stack_pop_float(stack); 39 | line = pd->last->ud; 40 | sp_line_init(pd->sp, line); 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | b = sporth_stack_pop_float(stack); 45 | dur = sporth_stack_pop_float(stack); 46 | a = sporth_stack_pop_float(stack); 47 | trig = sporth_stack_pop_float(stack); 48 | line = pd->last->ud; 49 | line->a = a; 50 | line->dur = dur; 51 | line->b = b; 52 | sp_line_compute(pd->sp, line, &trig, &out); 53 | sporth_stack_push_float(stack, out); 54 | break; 55 | case PLUMBER_DESTROY: 56 | line = pd->last->ud; 57 | sp_line_destroy(&line); 58 | break; 59 | default: 60 | plumber_print(pd, "line: Unknown mode!\n"); 61 | break; 62 | } 63 | return PLUMBER_OK; 64 | } 65 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/mode.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_mode(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT in; 7 | SPFLOAT out; 8 | SPFLOAT freq; 9 | SPFLOAT q; 10 | sp_mode *mode; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "mode: Creating\n"); 17 | #endif 18 | 19 | sp_mode_create(&mode); 20 | plumber_add_ugen(pd, SPORTH_MODE, mode); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for mode\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | q = sporth_stack_pop_float(stack); 27 | freq = sporth_stack_pop_float(stack); 28 | in = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "mode: Initialising\n"); 35 | #endif 36 | 37 | q = sporth_stack_pop_float(stack); 38 | freq = sporth_stack_pop_float(stack); 39 | in = sporth_stack_pop_float(stack); 40 | mode = pd->last->ud; 41 | sp_mode_init(pd->sp, mode); 42 | sporth_stack_push_float(stack, 0); 43 | break; 44 | case PLUMBER_COMPUTE: 45 | q = sporth_stack_pop_float(stack); 46 | freq = sporth_stack_pop_float(stack); 47 | in = sporth_stack_pop_float(stack); 48 | mode = pd->last->ud; 49 | mode->freq = freq; 50 | mode->q = q; 51 | sp_mode_compute(pd->sp, mode, &in, &out); 52 | sporth_stack_push_float(stack, out); 53 | break; 54 | case PLUMBER_DESTROY: 55 | mode = pd->last->ud; 56 | sp_mode_destroy(&mode); 57 | break; 58 | default: 59 | plumber_print(pd, "mode: Unknown mode!\n"); 60 | break; 61 | } 62 | return PLUMBER_OK; 63 | } 64 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/pan.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_pan2(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT in; 7 | SPFLOAT out_left; 8 | SPFLOAT out_right; 9 | SPFLOAT pan; 10 | sp_pan2 *pan2; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "pan2: Creating\n"); 17 | #endif 18 | 19 | sp_pan2_create(&pan2); 20 | plumber_add_ugen(pd, SPORTH_PAN, pan2); 21 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for pan2\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | pan = sporth_stack_pop_float(stack); 27 | in = sporth_stack_pop_float(stack); 28 | sporth_stack_push_float(stack, 0); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "pan2: Initialising\n"); 35 | #endif 36 | pan = sporth_stack_pop_float(stack); 37 | in = sporth_stack_pop_float(stack); 38 | pan2 = pd->last->ud; 39 | sp_pan2_init(pd->sp, pan2); 40 | sporth_stack_push_float(stack, 0); 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | pan = sporth_stack_pop_float(stack); 45 | in = sporth_stack_pop_float(stack); 46 | pan2 = pd->last->ud; 47 | pan2->pan = pan; 48 | sp_pan2_compute(pd->sp, pan2, &in, &out_left, &out_right); 49 | sporth_stack_push_float(stack, out_left); 50 | sporth_stack_push_float(stack, out_right); 51 | break; 52 | case PLUMBER_DESTROY: 53 | pan2 = pd->last->ud; 54 | sp_pan2_destroy(&pan2); 55 | break; 56 | default: 57 | plumber_print(pd, "pan2: Unknown mode!\n"); 58 | break; 59 | } 60 | return PLUMBER_OK; 61 | } 62 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/expon.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_expon(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT trig; 7 | SPFLOAT out; 8 | SPFLOAT a; 9 | SPFLOAT dur; 10 | SPFLOAT b; 11 | sp_expon *expon; 12 | 13 | switch(pd->mode) { 14 | case PLUMBER_CREATE: 15 | 16 | #ifdef DEBUG_MODE 17 | plumber_print(pd, "expon: Creating\n"); 18 | #endif 19 | 20 | sp_expon_create(&expon); 21 | plumber_add_ugen(pd, SPORTH_EXPON, expon); 22 | if(sporth_check_args(stack, "ffff") != SPORTH_OK) { 23 | plumber_print(pd,"Not enough arguments for expon\n"); 24 | stack->error++; 25 | return PLUMBER_NOTOK; 26 | } 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "expon: Initialising\n"); 33 | #endif 34 | 35 | b = sporth_stack_pop_float(stack); 36 | dur = sporth_stack_pop_float(stack); 37 | a = sporth_stack_pop_float(stack); 38 | trig = sporth_stack_pop_float(stack); 39 | expon = pd->last->ud; 40 | sp_expon_init(pd->sp, expon); 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | b = sporth_stack_pop_float(stack); 45 | dur = sporth_stack_pop_float(stack); 46 | a = sporth_stack_pop_float(stack); 47 | trig = sporth_stack_pop_float(stack); 48 | expon = pd->last->ud; 49 | expon->a = a; 50 | expon->dur = dur; 51 | expon->b = b; 52 | sp_expon_compute(pd->sp, expon, &trig, &out); 53 | sporth_stack_push_float(stack, out); 54 | break; 55 | case PLUMBER_DESTROY: 56 | expon = pd->last->ud; 57 | sp_expon_destroy(&expon); 58 | break; 59 | default: 60 | plumber_print(pd, "expon: Unknown mode!\n"); 61 | break; 62 | } 63 | return PLUMBER_OK; 64 | } 65 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/scale.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_scale(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT in; 7 | SPFLOAT out; 8 | SPFLOAT min; 9 | SPFLOAT max; 10 | sp_scale *scale; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "scale: Creating\n"); 17 | #endif 18 | 19 | sp_scale_create(&scale); 20 | plumber_add_ugen(pd, SPORTH_SCALE, scale); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for scale\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | max = sporth_stack_pop_float(stack); 27 | min = sporth_stack_pop_float(stack); 28 | in = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "scale: Initialising\n"); 35 | #endif 36 | max = sporth_stack_pop_float(stack); 37 | min = sporth_stack_pop_float(stack); 38 | in = sporth_stack_pop_float(stack); 39 | scale = pd->last->ud; 40 | sp_scale_init(pd->sp, scale); 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | max = sporth_stack_pop_float(stack); 45 | min = sporth_stack_pop_float(stack); 46 | in = sporth_stack_pop_float(stack); 47 | scale = pd->last->ud; 48 | scale->min = min; 49 | scale->max = max; 50 | sp_scale_compute(pd->sp, scale, &in, &out); 51 | sporth_stack_push_float(stack, out); 52 | break; 53 | case PLUMBER_DESTROY: 54 | scale = pd->last->ud; 55 | sp_scale_destroy(&scale); 56 | break; 57 | default: 58 | plumber_print(pd, "scale: Unknown mode!\n"); 59 | break; 60 | } 61 | return PLUMBER_OK; 62 | } 63 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/count.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_count(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT trig; 7 | SPFLOAT out; 8 | SPFLOAT count; 9 | SPFLOAT mode; 10 | sp_count *cnt; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "count: Creating\n"); 17 | #endif 18 | 19 | sp_count_create(&cnt); 20 | plumber_add_ugen(pd, SPORTH_COUNT, cnt); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for count\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | mode = sporth_stack_pop_float(stack); 27 | count = sporth_stack_pop_float(stack); 28 | trig = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "count: Initialising\n"); 35 | #endif 36 | mode = sporth_stack_pop_float(stack); 37 | count = sporth_stack_pop_float(stack); 38 | trig = sporth_stack_pop_float(stack); 39 | cnt = pd->last->ud; 40 | sp_count_init(pd->sp, cnt); 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | mode = sporth_stack_pop_float(stack); 45 | count = sporth_stack_pop_float(stack); 46 | trig = sporth_stack_pop_float(stack); 47 | cnt = pd->last->ud; 48 | cnt->count = count; 49 | cnt->mode = mode; 50 | sp_count_compute(pd->sp, cnt, &trig, &out); 51 | sporth_stack_push_float(stack, out); 52 | break; 53 | case PLUMBER_DESTROY: 54 | cnt = pd->last->ud; 55 | sp_count_destroy(&cnt); 56 | break; 57 | default: 58 | plumber_print(pd, "count: Unknown mode!\n"); 59 | break; 60 | } 61 | return PLUMBER_OK; 62 | } 63 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/trand.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_trand(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT trig; 7 | SPFLOAT out; 8 | SPFLOAT min; 9 | SPFLOAT max; 10 | sp_trand *trand; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "trand: Creating\n"); 17 | #endif 18 | 19 | sp_trand_create(&trand); 20 | plumber_add_ugen(pd, SPORTH_TRAND, trand); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for trand\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | max = sporth_stack_pop_float(stack); 27 | min = sporth_stack_pop_float(stack); 28 | trig = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "trand: Initialising\n"); 35 | #endif 36 | max = sporth_stack_pop_float(stack); 37 | min = sporth_stack_pop_float(stack); 38 | trig = sporth_stack_pop_float(stack); 39 | trand = pd->last->ud; 40 | sp_trand_init(pd->sp, trand); 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | max = sporth_stack_pop_float(stack); 45 | min = sporth_stack_pop_float(stack); 46 | trig = sporth_stack_pop_float(stack); 47 | trand = pd->last->ud; 48 | trand->min = min; 49 | trand->max = max; 50 | sp_trand_compute(pd->sp, trand, &trig, &out); 51 | sporth_stack_push_float(stack, out); 52 | break; 53 | case PLUMBER_DESTROY: 54 | trand = pd->last->ud; 55 | sp_trand_destroy(&trand); 56 | break; 57 | default: 58 | plumber_print(pd, "trand: Unknown mode!\n"); 59 | break; 60 | } 61 | return PLUMBER_OK; 62 | } 63 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/comb.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_comb(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT out; 8 | SPFLOAT looptime; 9 | SPFLOAT revtime; 10 | sp_comb *comb; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "comb: Creating\n"); 17 | #endif 18 | 19 | sp_comb_create(&comb); 20 | plumber_add_ugen(pd, SPORTH_COMB, comb); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for comb\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | looptime = sporth_stack_pop_float(stack); 27 | revtime = sporth_stack_pop_float(stack); 28 | input = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "comb: Initialising\n"); 35 | #endif 36 | 37 | looptime = sporth_stack_pop_float(stack); 38 | revtime = sporth_stack_pop_float(stack); 39 | input = sporth_stack_pop_float(stack); 40 | comb = pd->last->ud; 41 | sp_comb_init(pd->sp, comb, looptime); 42 | sporth_stack_push_float(stack, 0); 43 | break; 44 | case PLUMBER_COMPUTE: 45 | looptime = sporth_stack_pop_float(stack); 46 | revtime = sporth_stack_pop_float(stack); 47 | input = sporth_stack_pop_float(stack); 48 | comb = pd->last->ud; 49 | comb->revtime = revtime; 50 | sp_comb_compute(pd->sp, comb, &input, &out); 51 | sporth_stack_push_float(stack, out); 52 | break; 53 | case PLUMBER_DESTROY: 54 | comb = pd->last->ud; 55 | sp_comb_destroy(&comb); 56 | break; 57 | default: 58 | plumber_print(pd, "comb: Unknown mode!\n"); 59 | break; 60 | } 61 | return PLUMBER_OK; 62 | } 63 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/tenv2.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_tenv2(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT trig; 7 | SPFLOAT out; 8 | SPFLOAT atk; 9 | SPFLOAT rel; 10 | sp_tenv2 *tenv2; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "tenv2: Creating\n"); 17 | #endif 18 | 19 | sp_tenv2_create(&tenv2); 20 | plumber_add_ugen(pd, SPORTH_TENV2, tenv2); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for tenv2\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | rel = sporth_stack_pop_float(stack); 27 | atk = sporth_stack_pop_float(stack); 28 | trig = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "tenv2: Initialising\n"); 35 | #endif 36 | 37 | rel = sporth_stack_pop_float(stack); 38 | atk = sporth_stack_pop_float(stack); 39 | trig = sporth_stack_pop_float(stack); 40 | tenv2 = pd->last->ud; 41 | sp_tenv2_init(pd->sp, tenv2); 42 | sporth_stack_push_float(stack, 0); 43 | break; 44 | case PLUMBER_COMPUTE: 45 | rel = sporth_stack_pop_float(stack); 46 | atk = sporth_stack_pop_float(stack); 47 | trig = sporth_stack_pop_float(stack); 48 | tenv2 = pd->last->ud; 49 | tenv2->atk = atk; 50 | tenv2->rel = rel; 51 | sp_tenv2_compute(pd->sp, tenv2, &trig, &out); 52 | sporth_stack_push_float(stack, out); 53 | break; 54 | case PLUMBER_DESTROY: 55 | tenv2 = pd->last->ud; 56 | sp_tenv2_destroy(&tenv2); 57 | break; 58 | default: 59 | plumber_print(pd, "tenv2: Unknown mode!\n"); 60 | break; 61 | } 62 | return PLUMBER_OK; 63 | } 64 | -------------------------------------------------------------------------------- /Sources/Sporth/hash.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "Sporth.h" 7 | 8 | uint32_t sporth_hash(const char *str) 9 | { 10 | uint32_t h = 5381; 11 | while(*str) 12 | { 13 | h = ((h << 5) + h) ^ str[0]; 14 | h %= 0x7FFFFFFF; 15 | str++; 16 | } 17 | 18 | return h % 256; 19 | } 20 | 21 | int sporth_search(sporth_htable *ht, const char *key, uint32_t *val) 22 | { 23 | uint32_t pos = sporth_hash(key); 24 | sporth_list *list = &ht->list[pos]; 25 | uint32_t i; 26 | sporth_entry *entry = list->root.next;; 27 | for(i = 0; i < list->count; i++) { 28 | if(!strcmp(entry->key, key)) { 29 | *val = entry->val; 30 | return SPORTH_OK; 31 | } 32 | entry = entry->next; 33 | } 34 | 35 | return SPORTH_NOTOK; 36 | } 37 | 38 | int sporth_htable_add(sporth_htable *ht, const char *key, uint32_t val) 39 | { 40 | uint32_t pos = sporth_hash(key); 41 | 42 | sporth_list *list = &ht->list[pos]; 43 | list->count++; 44 | sporth_entry *old = list->last; 45 | sporth_entry *new = malloc(sizeof(sporth_entry)); 46 | new->val = val; 47 | new->key = malloc(sizeof(char) * (strlen(key) + 1)); 48 | strcpy(new->key, key); 49 | old->next = new; 50 | list->last = new; 51 | 52 | return SPORTH_OK; 53 | } 54 | 55 | int sporth_htable_init(sporth_htable *ht) 56 | { 57 | sporth_list *list; 58 | int i; 59 | 60 | for(i = 0; i < 256; i++) { 61 | list = &ht->list[i]; 62 | list->last = &list->root; 63 | list->count = 0; 64 | } 65 | 66 | return SPORTH_OK; 67 | } 68 | 69 | int sporth_htable_destroy(sporth_htable *ht) 70 | { 71 | sporth_list *list; 72 | sporth_entry *entry, *next; 73 | int i, j; 74 | 75 | for(i = 0; i < 256; i++) { 76 | list = &ht->list[i]; 77 | entry = list->root.next; 78 | for(j = 0; j < list->count; j++) { 79 | next = entry->next; 80 | free(entry->key); 81 | free(entry); 82 | entry = next; 83 | } 84 | } 85 | 86 | return SPORTH_OK; 87 | } 88 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/tdiv.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_tdiv(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT trigger; 7 | SPFLOAT out; 8 | SPFLOAT num; 9 | SPFLOAT offset; 10 | sp_tdiv *tdiv; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "tdiv: Creating\n"); 17 | #endif 18 | 19 | sp_tdiv_create(&tdiv); 20 | plumber_add_ugen(pd, SPORTH_TDIV, tdiv); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for tdiv\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | offset = sporth_stack_pop_float(stack); 27 | num = sporth_stack_pop_float(stack); 28 | trigger = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "tdiv: Initialising\n"); 35 | #endif 36 | 37 | offset = sporth_stack_pop_float(stack); 38 | num = sporth_stack_pop_float(stack); 39 | trigger = sporth_stack_pop_float(stack); 40 | tdiv = pd->last->ud; 41 | sp_tdiv_init(pd->sp, tdiv); 42 | sporth_stack_push_float(stack, 0); 43 | break; 44 | case PLUMBER_COMPUTE: 45 | offset = sporth_stack_pop_float(stack); 46 | num = sporth_stack_pop_float(stack); 47 | trigger = sporth_stack_pop_float(stack); 48 | tdiv = pd->last->ud; 49 | tdiv->num = num; 50 | tdiv->offset = offset; 51 | sp_tdiv_compute(pd->sp, tdiv, &trigger, &out); 52 | sporth_stack_push_float(stack, out); 53 | break; 54 | case PLUMBER_DESTROY: 55 | tdiv = pd->last->ud; 56 | sp_tdiv_destroy(&tdiv); 57 | break; 58 | default: 59 | plumber_print(pd, "tdiv: Unknown mode!\n"); 60 | break; 61 | } 62 | return PLUMBER_OK; 63 | } 64 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/lpf18.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_lpf18(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT in; 7 | SPFLOAT out; 8 | SPFLOAT cutoff; 9 | SPFLOAT res; 10 | SPFLOAT dist; 11 | sp_lpf18 *lpf18; 12 | 13 | switch(pd->mode) { 14 | case PLUMBER_CREATE: 15 | 16 | #ifdef DEBUG_MODE 17 | plumber_print(pd, "lpf18: Creating\n"); 18 | #endif 19 | 20 | sp_lpf18_create(&lpf18); 21 | plumber_add_ugen(pd, SPORTH_LPF18, lpf18); 22 | if(sporth_check_args(stack, "ffff") != SPORTH_OK) { 23 | plumber_print(pd,"Not enough arguments for lpf18\n"); 24 | stack->error++; 25 | return PLUMBER_NOTOK; 26 | } 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "lpf18: Initialising\n"); 33 | #endif 34 | 35 | dist = sporth_stack_pop_float(stack); 36 | res = sporth_stack_pop_float(stack); 37 | cutoff = sporth_stack_pop_float(stack); 38 | in = sporth_stack_pop_float(stack); 39 | lpf18 = pd->last->ud; 40 | sp_lpf18_init(pd->sp, lpf18); 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | dist = sporth_stack_pop_float(stack); 45 | res = sporth_stack_pop_float(stack); 46 | cutoff = sporth_stack_pop_float(stack); 47 | in = sporth_stack_pop_float(stack); 48 | lpf18 = pd->last->ud; 49 | lpf18->cutoff = cutoff; 50 | lpf18->res = res; 51 | lpf18->dist = dist; 52 | sp_lpf18_compute(pd->sp, lpf18, &in, &out); 53 | sporth_stack_push_float(stack, out); 54 | break; 55 | case PLUMBER_DESTROY: 56 | lpf18 = pd->last->ud; 57 | sp_lpf18_destroy(&lpf18); 58 | break; 59 | default: 60 | plumber_print(pd, "lpf18: Unknown mode!\n"); 61 | break; 62 | } 63 | return PLUMBER_OK; 64 | } 65 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/reson.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_reson(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT output; 8 | SPFLOAT freq; 9 | SPFLOAT bw; 10 | sp_reson *reson; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "reson: Creating\n"); 17 | #endif 18 | 19 | sp_reson_create(&reson); 20 | plumber_add_ugen(pd, SPORTH_RESON, reson); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for reson\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | bw = sporth_stack_pop_float(stack); 27 | freq = sporth_stack_pop_float(stack); 28 | input = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "reson: Initialising\n"); 35 | #endif 36 | 37 | bw = sporth_stack_pop_float(stack); 38 | freq = sporth_stack_pop_float(stack); 39 | input = sporth_stack_pop_float(stack); 40 | reson = pd->last->ud; 41 | sp_reson_init(pd->sp, reson); 42 | sporth_stack_push_float(stack, 0); 43 | break; 44 | case PLUMBER_COMPUTE: 45 | bw = sporth_stack_pop_float(stack); 46 | freq = sporth_stack_pop_float(stack); 47 | input = sporth_stack_pop_float(stack); 48 | reson = pd->last->ud; 49 | reson->freq = freq; 50 | reson->bw = bw; 51 | sp_reson_compute(pd->sp, reson, &input, &output); 52 | sporth_stack_push_float(stack, output); 53 | break; 54 | case PLUMBER_DESTROY: 55 | reson = pd->last->ud; 56 | sp_reson_destroy(&reson); 57 | break; 58 | default: 59 | plumber_print(pd, "reson: Unknown mode!\n"); 60 | break; 61 | } 62 | return PLUMBER_OK; 63 | } 64 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/clock.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_clock(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT trig; 7 | SPFLOAT out; 8 | SPFLOAT bpm; 9 | SPFLOAT subdiv; 10 | sp_clock *clock; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "clock: Creating\n"); 17 | #endif 18 | 19 | sp_clock_create(&clock); 20 | plumber_add_ugen(pd, SPORTH_CLOCK, clock); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for clock\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | subdiv = sporth_stack_pop_float(stack); 27 | bpm = sporth_stack_pop_float(stack); 28 | trig = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "clock: Initialising\n"); 35 | #endif 36 | 37 | subdiv = sporth_stack_pop_float(stack); 38 | bpm = sporth_stack_pop_float(stack); 39 | trig = sporth_stack_pop_float(stack); 40 | clock = pd->last->ud; 41 | sp_clock_init(pd->sp, clock); 42 | sporth_stack_push_float(stack, 0); 43 | break; 44 | case PLUMBER_COMPUTE: 45 | subdiv = sporth_stack_pop_float(stack); 46 | bpm = sporth_stack_pop_float(stack); 47 | trig = sporth_stack_pop_float(stack); 48 | clock = pd->last->ud; 49 | clock->bpm = bpm; 50 | clock->subdiv = subdiv; 51 | sp_clock_compute(pd->sp, clock, &trig, &out); 52 | sporth_stack_push_float(stack, out); 53 | break; 54 | case PLUMBER_DESTROY: 55 | clock = pd->last->ud; 56 | sp_clock_destroy(&clock); 57 | break; 58 | default: 59 | plumber_print(pd, "clock: Unknown mode!\n"); 60 | break; 61 | } 62 | return PLUMBER_OK; 63 | } 64 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/eqfil.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_eqfil(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT output; 8 | SPFLOAT freq; 9 | SPFLOAT bw; 10 | SPFLOAT gain; 11 | sp_eqfil *eqfil; 12 | 13 | switch(pd->mode) { 14 | case PLUMBER_CREATE: 15 | 16 | #ifdef DEBUG_MODE 17 | plumber_print(pd, "eqfil: Creating\n"); 18 | #endif 19 | 20 | sp_eqfil_create(&eqfil); 21 | plumber_add_ugen(pd, SPORTH_EQFIL, eqfil); 22 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 23 | plumber_print(pd,"Not enough arguments for eqfil\n"); 24 | stack->error++; 25 | return PLUMBER_NOTOK; 26 | } 27 | sporth_stack_push_float(stack, 0); 28 | break; 29 | case PLUMBER_INIT: 30 | 31 | #ifdef DEBUG_MODE 32 | plumber_print(pd, "eqfil: Initialising\n"); 33 | #endif 34 | 35 | gain = sporth_stack_pop_float(stack); 36 | bw = sporth_stack_pop_float(stack); 37 | freq = sporth_stack_pop_float(stack); 38 | input = sporth_stack_pop_float(stack); 39 | eqfil = pd->last->ud; 40 | sp_eqfil_init(pd->sp, eqfil); 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | gain = sporth_stack_pop_float(stack); 45 | bw = sporth_stack_pop_float(stack); 46 | freq = sporth_stack_pop_float(stack); 47 | input = sporth_stack_pop_float(stack); 48 | eqfil = pd->last->ud; 49 | eqfil->freq = freq; 50 | eqfil->bw = bw; 51 | eqfil->gain = gain; 52 | sp_eqfil_compute(pd->sp, eqfil, &input, &output); 53 | sporth_stack_push_float(stack, output); 54 | break; 55 | case PLUMBER_DESTROY: 56 | eqfil = pd->last->ud; 57 | sp_eqfil_destroy(&eqfil); 58 | break; 59 | default: 60 | plumber_print(pd, "eqfil: Unknown mode!\n"); 61 | break; 62 | } 63 | return PLUMBER_OK; 64 | } 65 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/rspline.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_rspline(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT out; 7 | SPFLOAT min; 8 | SPFLOAT max; 9 | SPFLOAT cps_min; 10 | SPFLOAT cps_max; 11 | sp_rspline *rspline; 12 | 13 | switch(pd->mode) { 14 | case PLUMBER_CREATE: 15 | sp_rspline_create(&rspline); 16 | plumber_add_ugen(pd, SPORTH_RSPLINE, rspline); 17 | if(sporth_check_args(stack, "ffff") != SPORTH_OK) { 18 | plumber_print(pd,"Not enough arguments for rspline\n"); 19 | stack->error++; 20 | return PLUMBER_NOTOK; 21 | } 22 | cps_max = sporth_stack_pop_float(stack); 23 | cps_min = sporth_stack_pop_float(stack); 24 | max = sporth_stack_pop_float(stack); 25 | min = sporth_stack_pop_float(stack); 26 | sporth_stack_push_float(stack, 0); 27 | break; 28 | case PLUMBER_INIT: 29 | cps_max = sporth_stack_pop_float(stack); 30 | cps_min = sporth_stack_pop_float(stack); 31 | max = sporth_stack_pop_float(stack); 32 | min = sporth_stack_pop_float(stack); 33 | rspline = pd->last->ud; 34 | sp_rspline_init(pd->sp, rspline); 35 | sporth_stack_push_float(stack, 0); 36 | break; 37 | case PLUMBER_COMPUTE: 38 | cps_max = sporth_stack_pop_float(stack); 39 | cps_min = sporth_stack_pop_float(stack); 40 | max = sporth_stack_pop_float(stack); 41 | min = sporth_stack_pop_float(stack); 42 | rspline = pd->last->ud; 43 | rspline->min = min; 44 | rspline->max = max; 45 | rspline->cps_min = cps_min; 46 | rspline->cps_max = cps_max; 47 | sp_rspline_compute(pd->sp, rspline, NULL, &out); 48 | sporth_stack_push_float(stack, out); 49 | break; 50 | case PLUMBER_DESTROY: 51 | rspline = pd->last->ud; 52 | sp_rspline_destroy(&rspline); 53 | break; 54 | } 55 | return PLUMBER_OK; 56 | } 57 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/diode.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_diode(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT out_left; 8 | SPFLOAT freq; 9 | SPFLOAT res; 10 | sp_diode *diode; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "diode: Creating\n"); 17 | #endif 18 | 19 | sp_diode_create(&diode); 20 | plumber_add_ugen(pd, SPORTH_DIODE, diode); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for diode\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | res = sporth_stack_pop_float(stack); 27 | freq = sporth_stack_pop_float(stack); 28 | input = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "diode: Initialising\n"); 35 | #endif 36 | 37 | res = sporth_stack_pop_float(stack); 38 | freq = sporth_stack_pop_float(stack); 39 | input = sporth_stack_pop_float(stack); 40 | diode = pd->last->ud; 41 | sp_diode_init(pd->sp, diode); 42 | sporth_stack_push_float(stack, 0); 43 | break; 44 | case PLUMBER_COMPUTE: 45 | res = sporth_stack_pop_float(stack); 46 | freq = sporth_stack_pop_float(stack); 47 | input = sporth_stack_pop_float(stack); 48 | diode = pd->last->ud; 49 | diode->freq = freq; 50 | diode->res = res; 51 | sp_diode_compute(pd->sp, diode, &input, &out_left); 52 | sporth_stack_push_float(stack, out_left); 53 | break; 54 | case PLUMBER_DESTROY: 55 | diode = pd->last->ud; 56 | sp_diode_destroy(&diode); 57 | break; 58 | default: 59 | plumber_print(pd, "diode: Unknown mode!\n"); 60 | break; 61 | } 62 | return PLUMBER_OK; 63 | } 64 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/randi.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_randi(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT out; 7 | SPFLOAT min; 8 | SPFLOAT max; 9 | SPFLOAT cps; 10 | sp_randi *randi; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "randi: Creating\n"); 17 | #endif 18 | 19 | sp_randi_create(&randi); 20 | plumber_add_ugen(pd, SPORTH_RANDI, randi); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for randi\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | cps = sporth_stack_pop_float(stack); 27 | max = sporth_stack_pop_float(stack); 28 | min = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "randi: Initialising\n"); 35 | #endif 36 | cps = sporth_stack_pop_float(stack); 37 | max = sporth_stack_pop_float(stack); 38 | min = sporth_stack_pop_float(stack); 39 | randi = pd->last->ud; 40 | sp_randi_init(pd->sp, randi); 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | cps = sporth_stack_pop_float(stack); 45 | max = sporth_stack_pop_float(stack); 46 | min = sporth_stack_pop_float(stack); 47 | randi = pd->last->ud; 48 | randi->min = min; 49 | randi->max = max; 50 | randi->cps = cps; 51 | sp_randi_compute(pd->sp, randi, NULL, &out); 52 | sporth_stack_push_float(stack, out); 53 | break; 54 | case PLUMBER_DESTROY: 55 | randi = pd->last->ud; 56 | sp_randi_destroy(&randi); 57 | break; 58 | default: 59 | plumber_print(pd, "randi: Unknown mode!\n"); 60 | break; 61 | } 62 | return PLUMBER_OK; 63 | } 64 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/waveset.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_waveset(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT out; 8 | SPFLOAT ilen; 9 | SPFLOAT rep; 10 | sp_waveset *waveset; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "waveset: Creating\n"); 17 | #endif 18 | 19 | sp_waveset_create(&waveset); 20 | plumber_add_ugen(pd, SPORTH_WAVESET, waveset); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for waveset\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | ilen = sporth_stack_pop_float(stack); 27 | rep = sporth_stack_pop_float(stack); 28 | input = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "waveset: Initialising\n"); 35 | #endif 36 | 37 | ilen = sporth_stack_pop_float(stack); 38 | rep = sporth_stack_pop_float(stack); 39 | input = sporth_stack_pop_float(stack); 40 | waveset = pd->last->ud; 41 | sp_waveset_init(pd->sp, waveset, ilen); 42 | sporth_stack_push_float(stack, 0); 43 | break; 44 | case PLUMBER_COMPUTE: 45 | ilen = sporth_stack_pop_float(stack); 46 | rep = sporth_stack_pop_float(stack); 47 | input = sporth_stack_pop_float(stack); 48 | waveset = pd->last->ud; 49 | waveset->rep = rep; 50 | sp_waveset_compute(pd->sp, waveset, &input, &out); 51 | sporth_stack_push_float(stack, out); 52 | break; 53 | case PLUMBER_DESTROY: 54 | waveset = pd->last->ud; 55 | sp_waveset_destroy(&waveset); 56 | break; 57 | default: 58 | plumber_print(pd, "waveset: Unknown mode!\n"); 59 | break; 60 | } 61 | return PLUMBER_OK; 62 | } 63 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/biscale.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_biscale(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT in; 7 | SPFLOAT out; 8 | SPFLOAT min; 9 | SPFLOAT max; 10 | sp_biscale *biscale; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "biscale: Creating\n"); 17 | #endif 18 | 19 | sp_biscale_create(&biscale); 20 | plumber_add_ugen(pd, SPORTH_BISCALE, biscale); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for biscale\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | max = sporth_stack_pop_float(stack); 27 | min = sporth_stack_pop_float(stack); 28 | in = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "biscale: Initialising\n"); 35 | #endif 36 | max = sporth_stack_pop_float(stack); 37 | min = sporth_stack_pop_float(stack); 38 | in = sporth_stack_pop_float(stack); 39 | biscale = pd->last->ud; 40 | sp_biscale_init(pd->sp, biscale); 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | max = sporth_stack_pop_float(stack); 45 | min = sporth_stack_pop_float(stack); 46 | in = sporth_stack_pop_float(stack); 47 | biscale = pd->last->ud; 48 | biscale->min = min; 49 | biscale->max = max; 50 | sp_biscale_compute(pd->sp, biscale, &in, &out); 51 | sporth_stack_push_float(stack, out); 52 | break; 53 | case PLUMBER_DESTROY: 54 | biscale = pd->last->ud; 55 | sp_biscale_destroy(&biscale); 56 | break; 57 | default: 58 | plumber_print(pd, "biscale: Unknown mode!\n"); 59 | break; 60 | } 61 | return PLUMBER_OK; 62 | } 63 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/randh.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_randh(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT out; 7 | SPFLOAT freq; 8 | SPFLOAT min; 9 | SPFLOAT max; 10 | sp_randh *randh; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "randh: Creating\n"); 17 | #endif 18 | 19 | sp_randh_create(&randh); 20 | plumber_add_ugen(pd, SPORTH_RANDH, randh); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for randh\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | freq = sporth_stack_pop_float(stack); 27 | max = sporth_stack_pop_float(stack); 28 | min = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "randh: Initialising\n"); 35 | #endif 36 | 37 | freq = sporth_stack_pop_float(stack); 38 | max = sporth_stack_pop_float(stack); 39 | min = sporth_stack_pop_float(stack); 40 | randh = pd->last->ud; 41 | sp_randh_init(pd->sp, randh); 42 | sporth_stack_push_float(stack, 0); 43 | break; 44 | case PLUMBER_COMPUTE: 45 | freq = sporth_stack_pop_float(stack); 46 | max = sporth_stack_pop_float(stack); 47 | min = sporth_stack_pop_float(stack); 48 | randh = pd->last->ud; 49 | randh->freq = freq; 50 | randh->min = min; 51 | randh->max = max; 52 | sp_randh_compute(pd->sp, randh, NULL, &out); 53 | sporth_stack_push_float(stack, out); 54 | break; 55 | case PLUMBER_DESTROY: 56 | randh = pd->last->ud; 57 | sp_randh_destroy(&randh); 58 | break; 59 | default: 60 | plumber_print(pd, "randh: Unknown mode!\n"); 61 | break; 62 | } 63 | return PLUMBER_OK; 64 | } 65 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/thresh.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_thresh(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT trig; 8 | SPFLOAT threshold; 9 | SPFLOAT mode; 10 | sp_thresh *thresh; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "thresh: Creating\n"); 17 | #endif 18 | 19 | sp_thresh_create(&thresh); 20 | plumber_add_ugen(pd, SPORTH_THRESH, thresh); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for thresh\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | sporth_stack_pop_float(stack); 27 | sporth_stack_pop_float(stack); 28 | sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "thresh: Initialising\n"); 35 | #endif 36 | 37 | mode = sporth_stack_pop_float(stack); 38 | threshold = sporth_stack_pop_float(stack); 39 | input = sporth_stack_pop_float(stack); 40 | thresh = pd->last->ud; 41 | sp_thresh_init(pd->sp, thresh); 42 | sporth_stack_push_float(stack, 0); 43 | break; 44 | case PLUMBER_COMPUTE: 45 | mode = sporth_stack_pop_float(stack); 46 | threshold = sporth_stack_pop_float(stack); 47 | input = sporth_stack_pop_float(stack); 48 | thresh = pd->last->ud; 49 | thresh->thresh = threshold; 50 | thresh->mode = mode; 51 | sp_thresh_compute(pd->sp, thresh, &input, &trig); 52 | sporth_stack_push_float(stack, trig); 53 | break; 54 | case PLUMBER_DESTROY: 55 | thresh = pd->last->ud; 56 | sp_thresh_destroy(&thresh); 57 | break; 58 | default: 59 | plumber_print(pd, "thresh: Unknown mode!\n"); 60 | break; 61 | } 62 | return PLUMBER_OK; 63 | } 64 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/crossfade.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_crossfade(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT in1; 7 | SPFLOAT in2; 8 | SPFLOAT out; 9 | SPFLOAT pos; 10 | sp_crossfade *crossfade; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "crossfade: Creating\n"); 17 | #endif 18 | 19 | sp_crossfade_create(&crossfade); 20 | plumber_add_ugen(pd, SPORTH_CROSSFADE, crossfade); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for crossfade\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | pos = sporth_stack_pop_float(stack); 27 | in1 = sporth_stack_pop_float(stack); 28 | in2 = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "crossfade: Initialising\n"); 35 | #endif 36 | 37 | pos = sporth_stack_pop_float(stack); 38 | in1 = sporth_stack_pop_float(stack); 39 | in2 = sporth_stack_pop_float(stack); 40 | crossfade = pd->last->ud; 41 | sp_crossfade_init(pd->sp, crossfade); 42 | sporth_stack_push_float(stack, 0); 43 | break; 44 | case PLUMBER_COMPUTE: 45 | pos = sporth_stack_pop_float(stack); 46 | in1 = sporth_stack_pop_float(stack); 47 | in2 = sporth_stack_pop_float(stack); 48 | crossfade = pd->last->ud; 49 | crossfade->pos = pos; 50 | sp_crossfade_compute(pd->sp, crossfade, &in1, &in2, &out); 51 | sporth_stack_push_float(stack, out); 52 | break; 53 | case PLUMBER_DESTROY: 54 | crossfade = pd->last->ud; 55 | sp_crossfade_destroy(&crossfade); 56 | break; 57 | default: 58 | plumber_print(pd, "crossfade: Unknown mode!\n"); 59 | break; 60 | } 61 | return PLUMBER_OK; 62 | } 63 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/allpass.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_allpass(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT out; 8 | SPFLOAT looptime; 9 | SPFLOAT revtime; 10 | sp_allpass *allpass; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "allpass: Creating\n"); 17 | #endif 18 | 19 | sp_allpass_create(&allpass); 20 | plumber_add_ugen(pd, SPORTH_ALLPASS, allpass); 21 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for allpass\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | looptime = sporth_stack_pop_float(stack); 27 | revtime = sporth_stack_pop_float(stack); 28 | input = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "allpass: Initialising\n"); 35 | #endif 36 | 37 | looptime = sporth_stack_pop_float(stack); 38 | revtime = sporth_stack_pop_float(stack); 39 | input = sporth_stack_pop_float(stack); 40 | allpass = pd->last->ud; 41 | sp_allpass_init(pd->sp, allpass, looptime); 42 | sporth_stack_push_float(stack, 0); 43 | break; 44 | case PLUMBER_COMPUTE: 45 | looptime = sporth_stack_pop_float(stack); 46 | revtime = sporth_stack_pop_float(stack); 47 | input = sporth_stack_pop_float(stack); 48 | allpass = pd->last->ud; 49 | allpass->revtime = revtime; 50 | sp_allpass_compute(pd->sp, allpass, &input, &out); 51 | sporth_stack_push_float(stack, out); 52 | break; 53 | case PLUMBER_DESTROY: 54 | allpass = pd->last->ud; 55 | sp_allpass_destroy(&allpass); 56 | break; 57 | default: 58 | plumber_print(pd, "allpass: Unknown mode!\n"); 59 | break; 60 | } 61 | return PLUMBER_OK; 62 | } 63 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/gen_padsynth.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "plumber.h" 6 | 7 | int sporth_gen_padsynth(sporth_stack *stack, void *ud) 8 | { 9 | plumber_data *pd = ud; 10 | 11 | sp_ftbl *ft, *amps; 12 | const char *ftname, *ampname; 13 | uint32_t size; 14 | SPFLOAT freq, bw; 15 | 16 | switch(pd->mode){ 17 | case PLUMBER_CREATE: 18 | plumber_add_ugen(pd, SPORTH_GEN_PADSYNTH, NULL); 19 | if(sporth_check_args(stack, "sfffs") != SPORTH_OK) { 20 | plumber_print(pd,"Padsynth: not enough arguments for gen_padsynth\n"); 21 | return PLUMBER_NOTOK; 22 | } 23 | ampname = sporth_stack_pop_string(stack); 24 | bw = sporth_stack_pop_float(stack); 25 | freq = sporth_stack_pop_float(stack); 26 | size = (uint32_t)sporth_stack_pop_float(stack); 27 | ftname = sporth_stack_pop_string(stack); 28 | 29 | if(plumber_ftmap_search(pd, ampname, &s) == PLUMBER_NOTOK) { 30 | stack->error++; 31 | return PLUMBER_NOTOK; 32 | } 33 | 34 | 35 | sp_ftbl_create(pd->sp, &ft, size); 36 | 37 | #ifdef DEBUG_MODE 38 | plumber_print(pd,"Running padsynth function\n"); 39 | #endif 40 | sp_gen_padsynth(pd->sp, ft, amps, freq, bw); 41 | 42 | plumber_ftmap_add(pd, ftname, ft); 43 | break; 44 | 45 | case PLUMBER_INIT: 46 | ampname = sporth_stack_pop_string(stack); 47 | bw = sporth_stack_pop_float(stack); 48 | freq = sporth_stack_pop_float(stack); 49 | size = (uint32_t)sporth_stack_pop_float(stack); 50 | ftname = sporth_stack_pop_string(stack); 51 | break; 52 | 53 | case PLUMBER_COMPUTE: 54 | sporth_stack_pop_float(stack); 55 | sporth_stack_pop_float(stack); 56 | sporth_stack_pop_float(stack); 57 | break; 58 | 59 | case PLUMBER_DESTROY: 60 | break; 61 | 62 | default: 63 | plumber_print(pd,"Error: Unknown mode!"); 64 | break; 65 | } 66 | return PLUMBER_OK; 67 | } 68 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/jitter.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_jitter(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT out; 7 | SPFLOAT amp; 8 | SPFLOAT cpsMin; 9 | SPFLOAT cpsMax; 10 | sp_jitter *jitter; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "jitter: Creating\n"); 17 | #endif 18 | 19 | sp_jitter_create(&jitter); 20 | plumber_add_ugen(pd, SPORTH_JITTER, jitter); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for jitter\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | cpsMax = sporth_stack_pop_float(stack); 27 | cpsMin = sporth_stack_pop_float(stack); 28 | amp = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "jitter: Initialising\n"); 35 | #endif 36 | cpsMax = sporth_stack_pop_float(stack); 37 | cpsMin = sporth_stack_pop_float(stack); 38 | amp = sporth_stack_pop_float(stack); 39 | jitter = pd->last->ud; 40 | sp_jitter_init(pd->sp, jitter); 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | cpsMax = sporth_stack_pop_float(stack); 45 | cpsMin = sporth_stack_pop_float(stack); 46 | amp = sporth_stack_pop_float(stack); 47 | jitter = pd->last->ud; 48 | jitter->amp = amp; 49 | jitter->cpsMin = cpsMin; 50 | jitter->cpsMax = cpsMax; 51 | sp_jitter_compute(pd->sp, jitter, NULL, &out); 52 | sporth_stack_push_float(stack, out); 53 | break; 54 | case PLUMBER_DESTROY: 55 | jitter = pd->last->ud; 56 | sp_jitter_destroy(&jitter); 57 | break; 58 | default: 59 | plumber_print(pd, "jitter: Unknown mode!\n"); 60 | break; 61 | } 62 | return PLUMBER_OK; 63 | } 64 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/tenv.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_tenv(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | 7 | SPFLOAT trig, attack, hold, release; 8 | 9 | SPFLOAT out = 0; 10 | sp_tenv *data; 11 | 12 | switch(pd->mode){ 13 | case PLUMBER_CREATE: 14 | sp_tenv_create(&data); 15 | plumber_add_ugen(pd, SPORTH_TENV, data); 16 | if(sporth_check_args(stack, "ffff") != SPORTH_OK) { 17 | plumber_print(pd, "Init: not enough arguments for tenv\n"); 18 | return PLUMBER_NOTOK; 19 | } 20 | release = sporth_stack_pop_float(stack); 21 | hold = sporth_stack_pop_float(stack); 22 | attack = sporth_stack_pop_float(stack); 23 | trig = sporth_stack_pop_float(stack); 24 | 25 | sporth_stack_push_float(stack, 0); 26 | break; 27 | 28 | case PLUMBER_INIT: 29 | release = sporth_stack_pop_float(stack); 30 | hold = sporth_stack_pop_float(stack); 31 | attack = sporth_stack_pop_float(stack); 32 | trig = sporth_stack_pop_float(stack); 33 | data = pd->last->ud; 34 | sp_tenv_init(pd->sp, data); 35 | sporth_stack_push_float(stack, 0); 36 | break; 37 | 38 | case PLUMBER_COMPUTE: 39 | release = sporth_stack_pop_float(stack); 40 | hold = sporth_stack_pop_float(stack); 41 | attack = sporth_stack_pop_float(stack); 42 | trig = sporth_stack_pop_float(stack); 43 | 44 | data = pd->last->ud; 45 | data->atk = attack; 46 | data->rel = release; 47 | data->hold = hold; 48 | sp_tenv_compute(pd->sp, data, &trig, &out); 49 | sporth_stack_push_float(stack, out); 50 | break; 51 | 52 | case PLUMBER_DESTROY: 53 | #ifdef DEBUG_MODE 54 | plumber_print(pd, "Destroying tenv\n"); 55 | #endif 56 | data = pd->last->ud; 57 | sp_tenv_destroy(&data); 58 | break; 59 | 60 | default: 61 | plumber_print(pd, "Error: Unknown mode!"); 62 | break; 63 | } 64 | return PLUMBER_OK; 65 | } 66 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/streson.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_streson(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT output; 8 | SPFLOAT freq; 9 | SPFLOAT fdbgain; 10 | sp_streson *streson; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "streson: Creating\n"); 17 | #endif 18 | 19 | sp_streson_create(&streson); 20 | plumber_add_ugen(pd, SPORTH_STRESON, streson); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for streson\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | fdbgain = sporth_stack_pop_float(stack); 27 | freq = sporth_stack_pop_float(stack); 28 | input = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "streson: Initialising\n"); 35 | #endif 36 | 37 | fdbgain = sporth_stack_pop_float(stack); 38 | freq = sporth_stack_pop_float(stack); 39 | input = sporth_stack_pop_float(stack); 40 | streson = pd->last->ud; 41 | sp_streson_init(pd->sp, streson); 42 | sporth_stack_push_float(stack, 0); 43 | break; 44 | case PLUMBER_COMPUTE: 45 | fdbgain = sporth_stack_pop_float(stack); 46 | freq = sporth_stack_pop_float(stack); 47 | input = sporth_stack_pop_float(stack); 48 | streson = pd->last->ud; 49 | streson->freq = freq; 50 | streson->fdbgain = fdbgain; 51 | sp_streson_compute(pd->sp, streson, &input, &output); 52 | sporth_stack_push_float(stack, output); 53 | break; 54 | case PLUMBER_DESTROY: 55 | streson = pd->last->ud; 56 | sp_streson_destroy(&streson); 57 | break; 58 | default: 59 | plumber_print(pd, "streson: Unknown mode!\n"); 60 | break; 61 | } 62 | return PLUMBER_OK; 63 | } 64 | -------------------------------------------------------------------------------- /Sources/SporthAudioKit/Generators/Operation+PhysicalModels.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. 2 | 3 | public extension Operation { 4 | /// Karplus-Strong plucked string instrument. 5 | /// 6 | /// - Parameters: 7 | /// - trigger: Triggering operation 8 | /// - frequency: Variable frequency. Values less than the lowest frequency will be doubled until it is 9 | /// greater than that. (Default: 110, Minimum: 0, Maximum: 22000) 10 | /// - amplitude: Amplitude (Default: 0.5, Minimum: 0, Maximum: 1) 11 | /// - lowestFrequency: Sets the initial frequency. This frequency is used to allocate all the buffers needed for 12 | /// the delay. This should be the lowest frequency you plan on using. (Default: 110) 13 | /// 14 | static func pluckedString( 15 | trigger: Operation, 16 | frequency: OperationParameter = 110, 17 | amplitude: OperationParameter = 0.5, 18 | lowestFrequency: Double = 110 19 | ) -> Operation { 20 | return Operation(module: "pluck", 21 | inputs: trigger, frequency, amplitude, lowestFrequency) 22 | } 23 | 24 | /// Karplus-Strong plucked string instrument. 25 | /// 26 | /// - Parameters: 27 | /// - frequency: Glottal frequency. 28 | /// - tonguePosition: Tongue position (0-1) 29 | /// - tongueDiameter: Tongue diameter (0-1) 30 | /// - tenseness: Vocal tenseness. 0 = all breath. 1=fully saturated. 31 | /// - nasality: Sets the velum size. Larger values of this creates more nasally sounds. 32 | /// 33 | /// NOTE: This node is CPU intensitve and will drop packet if your buffer size is 34 | /// too short. It requires at least 64 samples on an iPhone X, for example. 35 | static func vocalTract( 36 | frequency: OperationParameter = 160.0, 37 | tonguePosition: OperationParameter = 0.5, 38 | tongueDiameter: OperationParameter = 1.0, 39 | tenseness: OperationParameter = 0.6, 40 | nasality: OperationParameter = 0.0 41 | ) -> Operation { 42 | return Operation(module: "voc", 43 | inputs: frequency, tonguePosition, tongueDiameter, tenseness, nasality) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/bitcrush.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_bitcrush(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT out; 8 | SPFLOAT bitdepth; 9 | SPFLOAT srate; 10 | sp_bitcrush *bitcrush; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "bitcrush: Creating\n"); 17 | #endif 18 | 19 | sp_bitcrush_create(&bitcrush); 20 | plumber_add_ugen(pd, SPORTH_BITCRUSH, bitcrush); 21 | if(sporth_check_args(stack, "ff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for bitcrush\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | srate = sporth_stack_pop_float(stack); 27 | bitdepth = sporth_stack_pop_float(stack); 28 | input = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "bitcrush: Initialising\n"); 35 | #endif 36 | srate = sporth_stack_pop_float(stack); 37 | bitdepth = sporth_stack_pop_float(stack); 38 | input = sporth_stack_pop_float(stack); 39 | bitcrush = pd->last->ud; 40 | sp_bitcrush_init(pd->sp, bitcrush); 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | srate = sporth_stack_pop_float(stack); 45 | bitdepth = sporth_stack_pop_float(stack); 46 | input = sporth_stack_pop_float(stack); 47 | bitcrush = pd->last->ud; 48 | bitcrush->bitdepth = bitdepth; 49 | bitcrush->srate = srate; 50 | sp_bitcrush_compute(pd->sp, bitcrush, &input, &out); 51 | sporth_stack_push_float(stack, out); 52 | break; 53 | case PLUMBER_DESTROY: 54 | bitcrush = pd->last->ud; 55 | sp_bitcrush_destroy(&bitcrush); 56 | break; 57 | default: 58 | plumber_print(pd, "bitcrush: Unknown mode!\n"); 59 | break; 60 | } 61 | return PLUMBER_OK; 62 | } 63 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/blsquare.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_blsquare(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT out; 7 | SPFLOAT freq; 8 | SPFLOAT amp; 9 | SPFLOAT width; 10 | sp_blsquare *blsquare; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "blsquare: Creating\n"); 17 | #endif 18 | 19 | sp_blsquare_create(&blsquare); 20 | plumber_add_ugen(pd, SPORTH_SQUARE, blsquare); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for blsquare\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | width = sporth_stack_pop_float(stack); 27 | amp = sporth_stack_pop_float(stack); 28 | freq = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "blsquare: Initialising\n"); 35 | #endif 36 | 37 | width = sporth_stack_pop_float(stack); 38 | amp = sporth_stack_pop_float(stack); 39 | freq = sporth_stack_pop_float(stack); 40 | blsquare = pd->last->ud; 41 | sp_blsquare_init(pd->sp, blsquare); 42 | sporth_stack_push_float(stack, 0); 43 | break; 44 | case PLUMBER_COMPUTE: 45 | width = sporth_stack_pop_float(stack); 46 | amp = sporth_stack_pop_float(stack); 47 | freq = sporth_stack_pop_float(stack); 48 | blsquare = pd->last->ud; 49 | *blsquare->freq = freq; 50 | *blsquare->amp = amp; 51 | *blsquare->width = width; 52 | sp_blsquare_compute(pd->sp, blsquare, NULL, &out); 53 | sporth_stack_push_float(stack, out); 54 | break; 55 | case PLUMBER_DESTROY: 56 | blsquare = pd->last->ud; 57 | sp_blsquare_destroy(&blsquare); 58 | break; 59 | default: 60 | plumber_print(pd, "blsquare: Unknown mode!\n"); 61 | break; 62 | } 63 | return PLUMBER_OK; 64 | } 65 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/moogladder.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_moogladder(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT input; 7 | SPFLOAT out; 8 | SPFLOAT freq; 9 | SPFLOAT res; 10 | sp_moogladder *moogladder; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "moogladder: Creating\n"); 17 | #endif 18 | 19 | sp_moogladder_create(&moogladder); 20 | plumber_add_ugen(pd, SPORTH_MOOGLADDER, moogladder); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for moogladder\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | res = sporth_stack_pop_float(stack); 27 | freq = sporth_stack_pop_float(stack); 28 | input = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "moogladder: Initialising\n"); 35 | #endif 36 | res = sporth_stack_pop_float(stack); 37 | freq = sporth_stack_pop_float(stack); 38 | input = sporth_stack_pop_float(stack); 39 | moogladder = pd->last->ud; 40 | sp_moogladder_init(pd->sp, moogladder); 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | res = sporth_stack_pop_float(stack); 45 | freq = sporth_stack_pop_float(stack); 46 | input = sporth_stack_pop_float(stack); 47 | moogladder = pd->last->ud; 48 | moogladder->freq = freq; 49 | moogladder->res = res; 50 | sp_moogladder_compute(pd->sp, moogladder, &input, &out); 51 | sporth_stack_push_float(stack, out); 52 | break; 53 | case PLUMBER_DESTROY: 54 | moogladder = pd->last->ud; 55 | sp_moogladder_destroy(&moogladder); 56 | break; 57 | default: 58 | plumber_print(pd, "moogladder: Unknown mode!\n"); 59 | break; 60 | } 61 | return PLUMBER_OK; 62 | } 63 | -------------------------------------------------------------------------------- /Sources/Sporth/ugens/tphasor.c: -------------------------------------------------------------------------------- 1 | #include "plumber.h" 2 | 3 | int sporth_tphasor(sporth_stack *stack, void *ud) 4 | { 5 | plumber_data *pd = ud; 6 | SPFLOAT out; 7 | SPFLOAT iphs; 8 | SPFLOAT freq; 9 | SPFLOAT trig; 10 | sp_phasor *tphasor; 11 | 12 | switch(pd->mode) { 13 | case PLUMBER_CREATE: 14 | 15 | #ifdef DEBUG_MODE 16 | plumber_print(pd, "tphasor: Creating\n"); 17 | #endif 18 | 19 | sp_phasor_create(&tphasor); 20 | plumber_add_ugen(pd, SPORTH_TPHASOR, tphasor); 21 | if(sporth_check_args(stack, "fff") != SPORTH_OK) { 22 | plumber_print(pd,"Not enough arguments for tphasor\n"); 23 | stack->error++; 24 | return PLUMBER_NOTOK; 25 | } 26 | iphs = sporth_stack_pop_float(stack); 27 | freq = sporth_stack_pop_float(stack); 28 | trig = sporth_stack_pop_float(stack); 29 | sporth_stack_push_float(stack, 0); 30 | break; 31 | case PLUMBER_INIT: 32 | 33 | #ifdef DEBUG_MODE 34 | plumber_print(pd, "tphasor: Initialising\n"); 35 | #endif 36 | iphs = sporth_stack_pop_float(stack); 37 | freq = sporth_stack_pop_float(stack); 38 | trig = sporth_stack_pop_float(stack); 39 | tphasor = pd->last->ud; 40 | sp_phasor_init(pd->sp, tphasor, iphs); 41 | sporth_stack_push_float(stack, 0); 42 | break; 43 | case PLUMBER_COMPUTE: 44 | iphs = sporth_stack_pop_float(stack); 45 | freq = sporth_stack_pop_float(stack); 46 | trig = sporth_stack_pop_float(stack); 47 | tphasor = pd->last->ud; 48 | tphasor->freq = freq; 49 | 50 | if(trig != 0) { 51 | tphasor->curphs = iphs; 52 | } 53 | 54 | sp_phasor_compute(pd->sp, tphasor, NULL, &out); 55 | sporth_stack_push_float(stack, out); 56 | break; 57 | case PLUMBER_DESTROY: 58 | tphasor = pd->last->ud; 59 | sp_phasor_destroy(&tphasor); 60 | break; 61 | default: 62 | plumber_print(pd, "tphasor: Unknown mode!\n"); 63 | break; 64 | } 65 | return PLUMBER_OK; 66 | } 67 | --------------------------------------------------------------------------------