├── .gitattributes ├── .github └── workflows │ └── pull_request.yml ├── .gitignore ├── .license_header_template ├── Guest ├── .build │ └── .gitkeep ├── .sourcekit-lsp │ └── config.json ├── Package.swift ├── Sources │ ├── Bass │ │ ├── Shared │ │ └── main.swift │ ├── HiHat │ │ ├── Shared │ │ └── main.swift │ ├── JavaScript │ │ ├── encoder.js │ │ └── index.js │ ├── Kick │ │ ├── Shared │ │ └── main.swift │ ├── Mix │ │ ├── Shared │ │ └── main.swift │ ├── Plotter │ │ ├── Canvas.swift │ │ ├── Plotter.swift │ │ └── main.swift │ ├── Shared │ │ ├── AudioBuffer.swift │ │ ├── AudioEncode.swift │ │ ├── DOMInterop.swift │ │ ├── Effects │ │ │ └── LadderFilter.swift │ │ ├── Instruments │ │ │ ├── Bass.swift │ │ │ ├── Drums.swift │ │ │ └── Sequencer.swift │ │ ├── Mixer.swift │ │ ├── MusicTheory │ │ │ └── Pitch.swift │ │ ├── Utilities │ │ │ ├── AttackHoldRelease.swift │ │ │ └── Modulator.swift │ │ └── Waveforms │ │ │ ├── Saw.swift │ │ │ ├── Signal.swift │ │ │ ├── Square.swift │ │ │ └── Triangle.swift │ ├── VultDSP │ │ ├── VultLibrary │ │ │ ├── phase.vult │ │ │ ├── tables.vult │ │ │ └── util.vult │ │ ├── ahr.vult │ │ ├── include │ │ │ └── waveforms.h │ │ ├── kick.vult │ │ ├── ladder.vult │ │ ├── noise.vult │ │ ├── out.cpp │ │ ├── out.h │ │ ├── out.tables.h │ │ ├── saturate.vult │ │ ├── sine.vult │ │ ├── swept.vult │ │ ├── triangle.vult │ │ ├── vultin.cpp │ │ └── vultin.h │ └── dlmalloc │ │ ├── include │ │ ├── __macro_PAGESIZE.h │ │ ├── endian.h │ │ ├── errno.h │ │ ├── features.h │ │ ├── malloc.h │ │ ├── string.h │ │ ├── unistd.h │ │ └── wasi_api.h │ │ └── src │ │ ├── abort.c │ │ ├── dlmalloc.c │ │ ├── errno.c │ │ ├── memcpy.c │ │ ├── memset.c │ │ ├── sbrk.c │ │ └── upstream_malloc.h ├── build.sh └── index.html ├── LICENSE-vendored.md ├── LICENSE.txt ├── README.md ├── ServerHost ├── .gitignore ├── Package.resolved ├── Package.swift ├── Public │ ├── .build │ ├── Sources │ │ └── JavaScript │ └── upload.html ├── Sources │ └── Server │ │ ├── App+Logger.swift │ │ ├── App+Router.swift │ │ ├── App.swift │ │ ├── IndexPage.swift │ │ └── MixedOutput.swift └── Tests │ └── ServerTests │ └── ServerTests.swift └── WATExample ├── Package.resolved ├── Package.swift ├── Sources └── WATExample │ └── main.swift ├── factorial-flat.wat └── factorial.wat /.gitattributes: -------------------------------------------------------------------------------- 1 | Guest/Sources/VultDSP/*.cpp linguist-generated 2 | Guest/Sources/VultDSP/*.h linguist-generated 3 | Guest/Sources/VultDSP/**/*.vult linguist-generated 4 | Guest/Sources/dlmalloc/** linguist-vendored 5 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: Pull request 2 | 3 | on: 4 | pull_request: 5 | types: [opened, reopened, synchronize] 6 | 7 | jobs: 8 | tests: 9 | name: Test 10 | uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main 11 | with: 12 | linux_build_command: "cd Guest && ./build.sh" 13 | linux_exclude_swift_versions: '[{"swift_version": "5.9"}, {"swift_version": "5.10"}]' 14 | enable_windows_checks: false 15 | soundness: 16 | name: Soundness 17 | uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main 18 | with: 19 | license_header_check_project_name: "Swift" 20 | api_breakage_check_enabled: false 21 | unacceptable_language_check_enabled: true 22 | license_header_check_enabled: false 23 | broken_symlink_check_enabled: true 24 | format_check_enabled: false 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .build 3 | .index-build 4 | /Packages 5 | /*.xcodeproj 6 | xcuserdata/ 7 | DerivedData/ 8 | .netrc 9 | .swiftpm 10 | tmp 11 | /Artifacts 12 | /Bundles 13 | .vscode 14 | -------------------------------------------------------------------------------- /.license_header_template: -------------------------------------------------------------------------------- 1 | @@===----------------------------------------------------------------------===@@ 2 | @@ 3 | @@ This source file is part of the Swift open source project 4 | @@ 5 | @@ Copyright (c) YEARS Apple Inc. and the Swift project authors 6 | @@ Licensed under Apache License v2.0 with Runtime Library Exception 7 | @@ 8 | @@ See https://swift.org/LICENSE.txt for license information 9 | @@ See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | @@ 11 | @@===----------------------------------------------------------------------===@@ 12 | -------------------------------------------------------------------------------- /Guest/.build/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Guest/.sourcekit-lsp/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "swiftPM": { 3 | "triple": "wasm32-unknown-none-wasm" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /Guest/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 6.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | //===----------------------------------------------------------------------===// 5 | // 6 | // This source file is part of the Swift open source project 7 | // 8 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 9 | // Licensed under Apache License v2.0 with Runtime Library Exception 10 | // 11 | // See http://swift.org/LICENSE.txt for license information 12 | // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 13 | // 14 | //===----------------------------------------------------------------------===// 15 | 16 | import PackageDescription 17 | 18 | let embeddedSwiftSettings: [SwiftSetting] = [ 19 | .enableExperimentalFeature("Embedded"), 20 | .enableExperimentalFeature("Extern"), 21 | .interoperabilityMode(.Cxx), 22 | .unsafeFlags(["-wmo", "-disable-cmo", "-Xfrontend", "-gnone", "-Xfrontend", "-disable-stack-protector"]), 23 | ] 24 | 25 | let embeddedCSettings: [CSetting] = [ 26 | .unsafeFlags(["-fdeclspec"]), 27 | ] 28 | 29 | let linkerSettings: [LinkerSetting] = [ 30 | .unsafeFlags([ 31 | "-Xclang-linker", "-nostdlib", 32 | "-Xlinker", "--no-entry", 33 | ]), 34 | ] 35 | 36 | let libcSettings: [CSetting] = [ 37 | .define("LACKS_TIME_H"), 38 | .define("LACKS_SYS_TYPES_H"), 39 | .define("LACKS_STDLIB_H"), 40 | .define("LACKS_STRING_H"), 41 | .define("LACKS_SYS_MMAN_H"), 42 | .define("LACKS_FCNTL_H"), 43 | .define("NO_MALLOC_STATS", to: "1"), 44 | .define("__wasilibc_unmodified_upstream"), 45 | ] 46 | 47 | let package = Package( 48 | name: "Guest", 49 | targets: [ 50 | // Targets are the basic building blocks of a package, defining a module or a test suite. 51 | // Targets can depend on other targets in this package and products from dependencies. 52 | .executableTarget( 53 | name: "Plotter", 54 | dependencies: ["dlmalloc"], 55 | cSettings: embeddedCSettings, 56 | swiftSettings: embeddedSwiftSettings, 57 | linkerSettings: linkerSettings 58 | ), 59 | .target(name: "VultDSP"), 60 | .target( 61 | name: "dlmalloc", 62 | cSettings: libcSettings 63 | ), 64 | ] 65 | ) 66 | 67 | for module in ["Kick", "HiHat", "Bass", "Mix"] { 68 | package.targets.append( 69 | .executableTarget( 70 | name: module, 71 | dependencies: ["VultDSP", "dlmalloc"], 72 | cSettings: embeddedCSettings, 73 | swiftSettings: embeddedSwiftSettings, 74 | linkerSettings: linkerSettings 75 | ) 76 | ) 77 | } 78 | -------------------------------------------------------------------------------- /Guest/Sources/Bass/Shared: -------------------------------------------------------------------------------- 1 | ../Shared -------------------------------------------------------------------------------- /Guest/Sources/Bass/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | @_expose(wasm, "main") 14 | @_cdecl("main") 15 | func main(contextIndex: Int) { 16 | var sequencedBass = Sequencer( 17 | instrument: Bass(), 18 | sequence: [ 19 | .noteOn(.c.octave(1)), .noteOff, .noteOn(.d.octave(1)), .noteOff, .noteOn(.e.octave(1)), 20 | .noteOff, .noteOn(.f.octave(1)), .noteOff, .noteOn(.g.octave(1)), .noteOff, .noteOn(.a.octave(1)), 21 | ], 22 | stepLengthInSeconds: 0.25 23 | ) 24 | 25 | let totalLengthInSeconds = 6 26 | 27 | let buffer = AudioBuffer( 28 | capacity: sampleRate * totalLengthInSeconds, 29 | source: &sequencedBass 30 | ) 31 | 32 | Audio.encode(contextIndex: contextIndex, buffer) 33 | } 34 | -------------------------------------------------------------------------------- /Guest/Sources/HiHat/Shared: -------------------------------------------------------------------------------- 1 | ../Shared -------------------------------------------------------------------------------- /Guest/Sources/HiHat/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | @_expose(wasm, "main") 14 | @_cdecl("main") 15 | func main(contextIndex: Int) { 16 | var sequencedHiHat = Sequencer( 17 | instrument: HiHat(), 18 | sequence: [ 19 | .noteOff, .noteOff, .noteOff, .noteOff, 20 | .noteOff, .noteOff, .noteOff, .noteOff, 21 | .noteOn(.c.octave(1)), .noteOff, .noteOn(.c.octave(1)), .noteOff, 22 | .noteOff, .noteOff, .noteOff, .noteOff, 23 | ], 24 | stepLengthInSeconds: 0.125 25 | ) 26 | 27 | let totalLengthInSeconds = 6 28 | 29 | let buffer = AudioBuffer( 30 | capacity: sampleRate * totalLengthInSeconds, 31 | source: &sequencedHiHat 32 | ) 33 | 34 | Audio.encode(contextIndex: contextIndex, buffer) 35 | } 36 | -------------------------------------------------------------------------------- /Guest/Sources/JavaScript/encoder.js: -------------------------------------------------------------------------------- 1 | /* The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Yuji Miyane 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 | 23 | var setString = function(view, offset, str) { 24 | var len = str.length; 25 | for (var i = 0; i < len; ++i) 26 | view.setUint8(offset + i, str.charCodeAt(i)); 27 | }; 28 | 29 | export const Encoder = function(sampleRate, numChannels) { 30 | this.sampleRate = sampleRate; 31 | this.numChannels = numChannels; 32 | this.numSamples = 0; 33 | this.dataViews = []; 34 | }; 35 | 36 | Encoder.prototype.encode = function(buffer) { 37 | var len = buffer[0].length, 38 | nCh = this.numChannels, 39 | view = new DataView(new ArrayBuffer(len * nCh * 2)), 40 | offset = 0; 41 | for (var i = 0; i < len; ++i) 42 | for (var ch = 0; ch < nCh; ++ch) { 43 | var x = buffer[ch][i] * 0x7fff; 44 | view.setInt16(offset, x < 0 ? Math.max(x, -0x8000) : Math.min(x, 0x7fff), true); 45 | offset += 2; 46 | } 47 | this.dataViews.push(view); 48 | this.numSamples += len; 49 | }; 50 | 51 | Encoder.prototype.finish = function() { 52 | var dataSize = this.numChannels * this.numSamples * 2, 53 | view = new DataView(new ArrayBuffer(44)); 54 | setString(view, 0, 'RIFF'); 55 | view.setUint32(4, 36 + dataSize, true); 56 | setString(view, 8, 'WAVE'); 57 | setString(view, 12, 'fmt '); 58 | view.setUint32(16, 16, true); 59 | view.setUint16(20, 1, true); 60 | view.setUint16(22, this.numChannels, true); 61 | view.setUint32(24, this.sampleRate, true); 62 | view.setUint32(28, this.sampleRate * 4, true); 63 | view.setUint16(32, this.numChannels * 2, true); 64 | view.setUint16(34, 16, true); 65 | setString(view, 36, 'data'); 66 | view.setUint32(40, dataSize, true); 67 | this.dataViews.unshift(view); 68 | var blob = new Blob(this.dataViews, { type: 'audio/wav' }); 69 | this.cleanup(); 70 | return blob; 71 | }; 72 | 73 | Encoder.prototype.cancel = Encoder.prototype.cleanup = function() { 74 | delete this.dataViews; 75 | }; -------------------------------------------------------------------------------- /Guest/Sources/JavaScript/index.js: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import { Encoder } from './encoder.js'; 14 | 15 | const decoder = new TextDecoder(); 16 | const loggerElement = document.getElementById('wasm-logger'); 17 | const moduleInstances = []; 18 | 19 | function wasmMemoryAsString(i, address, byteCount) { 20 | return decoder.decode(moduleInstances[i].exports.memory.buffer.slice(address, address + byteCount)); 21 | } 22 | 23 | function wasmMemoryAsFloat32Array(i, address, byteCount) { 24 | return new Float32Array(moduleInstances[i].exports.memory.buffer.slice(address, address + byteCount)); 25 | } 26 | 27 | const contexts = []; 28 | 29 | const canvasImports = { 30 | canvas: { 31 | beginPath: (i) => contexts[i].beginPath(), 32 | stroke: (i) => contexts[i].stroke(), 33 | moveTo: (i, x, y) => contexts[i].moveTo(x, y), 34 | lineTo: (i, x, y) => contexts[i].lineTo(x, y), 35 | }, 36 | } 37 | 38 | const plotterModule = await WebAssembly.instantiateStreaming( 39 | fetch(".build/wasm32-unknown-none-wasm/release/plotter.wasm"), 40 | { ...canvasImports } 41 | ); 42 | 43 | function encodeAndPlot(audioBuffer, context) { 44 | const wavEncoder = new Encoder(44100, 1); 45 | wavEncoder.encode([audioBuffer]); 46 | const blob = wavEncoder.finish(); 47 | 48 | const audioURL = URL.createObjectURL(blob); 49 | document.getElementsByClassName('audio')[context].setAttribute('src', audioURL); 50 | 51 | const byteCount = audioBuffer.length * 4; 52 | const bufferPointer = plotterExports.allocateAudioBuffer(byteCount); 53 | const memoryBytes = new Float32Array(plotterExports.memory.buffer); 54 | memoryBytes.set(audioBuffer, bufferPointer / 4); 55 | plotterExports.plot(context, 1000, 200, 10, bufferPointer, byteCount); 56 | plotterExports.free(bufferPointer); 57 | } 58 | 59 | const plotterExports = plotterModule.instance.exports; 60 | 61 | const audioImports = { 62 | audio: { 63 | encode: (i, address, byteCount) => { 64 | const audioBuffer = wasmMemoryAsFloat32Array(i, address, byteCount); 65 | 66 | encodeAndPlot(audioBuffer, i); 67 | }, 68 | }, 69 | }; 70 | 71 | const consoleImports = { 72 | console: { 73 | log: (i, address, byteCount) => { 74 | loggerElement.innerHTML = wasmMemoryAsString(i, address, byteCount); 75 | }, 76 | logInt: (x) => console.log(x), 77 | logFloat: (x) => console.log(x), 78 | } 79 | }; 80 | 81 | const pluginElements = document.getElementsByClassName("plugin"); 82 | 83 | for (let i = 0; i < pluginElements.length; ++i) { 84 | const element = pluginElements[i]; 85 | const canvasElement = element.getElementsByClassName("plotter")[0]; 86 | const canvasContext = canvasElement.getContext('2d'); 87 | canvasContext.strokeStyle = 'white'; 88 | 89 | contexts.push(canvasContext); 90 | 91 | const { instance } = await WebAssembly.instantiateStreaming( 92 | fetch(element.dataset.modulePath), 93 | { ...audioImports, ...consoleImports } 94 | ); 95 | 96 | moduleInstances.push(instance); 97 | 98 | instance.exports.main(i); 99 | } 100 | 101 | const mixElement = document.getElementById("tracks-mix"); 102 | 103 | if (mixElement) { 104 | const canvasElement = mixElement.getElementsByClassName("plotter")[0]; 105 | const canvasContext = canvasElement.getContext('2d'); 106 | canvasContext.strokeStyle = 'white'; 107 | 108 | contexts.push(canvasContext); 109 | 110 | const response = await fetch("/mix"); 111 | const responseBlob = await response.blob(); 112 | 113 | const audioBuffer = new Float32Array(await responseBlob.arrayBuffer()); 114 | 115 | encodeAndPlot(audioBuffer, contexts.length - 1); 116 | } 117 | -------------------------------------------------------------------------------- /Guest/Sources/Kick/Shared: -------------------------------------------------------------------------------- 1 | ../Shared -------------------------------------------------------------------------------- /Guest/Sources/Kick/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | @_expose(wasm, "main") 14 | @_cdecl("main") 15 | func main(contextIndex: Int) { 16 | var sequencedKick = Sequencer( 17 | instrument: Kick(), 18 | sequence: [.noteOff, .noteOn(.c.octave(1)), .noteOff, .noteOn(.c.octave(1))], 19 | stepLengthInSeconds: 0.25 20 | ) 21 | 22 | let totalLengthInSeconds = 6 23 | 24 | let buffer = AudioBuffer( 25 | capacity: sampleRate * totalLengthInSeconds, 26 | source: &sequencedKick 27 | ) 28 | 29 | Audio.encode(contextIndex: contextIndex, buffer) 30 | } 31 | -------------------------------------------------------------------------------- /Guest/Sources/Mix/Shared: -------------------------------------------------------------------------------- 1 | ../Shared -------------------------------------------------------------------------------- /Guest/Sources/Mix/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | @_expose(wasm, "main") 14 | @_cdecl("main") 15 | func main(contextIndex: Int) { 16 | let sequencedKick = Sequencer( 17 | instrument: Kick(), 18 | sequence: [.noteOff, .noteOn(.c.octave(1)), .noteOff, .noteOn(.c.octave(1))], 19 | stepLengthInSeconds: 0.25 20 | ) 21 | 22 | let sequencedHiHat = Sequencer( 23 | instrument: HiHat(), 24 | sequence: [ 25 | .noteOff, .noteOff, .noteOff, .noteOff, 26 | .noteOff, .noteOff, .noteOff, .noteOff, 27 | .noteOn(.c.octave(1)), .noteOff, .noteOn(.c.octave(1)), .noteOff, 28 | .noteOff, .noteOff, .noteOff, .noteOff, 29 | ], 30 | stepLengthInSeconds: 0.125 31 | ) 32 | 33 | let sequencedBass = Sequencer( 34 | instrument: Bass(), 35 | sequence: [ 36 | .noteOn(.c.octave(1)), .noteOff, .noteOn(.d.octave(1)), .noteOff, .noteOn(.e.octave(1)), 37 | .noteOff, .noteOn(.f.octave(1)), .noteOff, .noteOn(.g.octave(1)), .noteOff, .noteOn(.a.octave(1)), 38 | ], 39 | stepLengthInSeconds: 0.25 40 | ) 41 | 42 | let totalLengthInSeconds = 6 43 | 44 | var mixer = Mixer( 45 | source1: sequencedHiHat, 46 | volume1: 0.05, 47 | source2: sequencedKick, 48 | volume2: 0.6, 49 | source3: sequencedBass, 50 | volume3: 0.1 51 | ) 52 | 53 | let buffer = AudioBuffer( 54 | capacity: sampleRate * totalLengthInSeconds, 55 | source: &mixer 56 | ) 57 | 58 | Audio.encode(contextIndex: contextIndex, buffer) 59 | } 60 | -------------------------------------------------------------------------------- /Guest/Sources/Plotter/Canvas.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | /// Abstract implementation of line drawing on a canvas. Platform-specific 14 | /// implementation is required to provide these functions for drawing code in 15 | /// this module to work. 16 | protocol Canvas { 17 | static func beginPath(ctx: Int) 18 | static func stroke(ctx: Int) 19 | static func moveTo(ctx: Int, x: Int, y: Int) 20 | static func lineTo(ctx: Int, x: Int, y: Int) 21 | } 22 | 23 | struct HTMLCanvas: Canvas { 24 | @_extern(wasm, module: "canvas", name: "beginPath") 25 | @_extern(c) 26 | static func beginPath(ctx: Int) 27 | 28 | @_extern(wasm, module: "canvas", name: "stroke") 29 | @_extern(c) 30 | static func stroke(ctx: Int) 31 | 32 | @_extern(wasm, module: "canvas", name: "moveTo") 33 | @_extern(c) 34 | static func moveTo(ctx: Int, x: Int, y: Int) 35 | 36 | @_extern(wasm, module: "canvas", name: "lineTo") 37 | @_extern(c) 38 | static func lineTo(ctx: Int, x: Int, y: Int) 39 | } 40 | -------------------------------------------------------------------------------- /Guest/Sources/Plotter/Plotter.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | struct Plotter { 14 | let contextIndex: Int 15 | let height: Int 16 | let width: Int 17 | let centerY: Int 18 | let scaleFactor: Float 19 | 20 | init(contextIndex: Int, width: Int, height: Int, margin: Int) { 21 | self.contextIndex = contextIndex 22 | self.width = width 23 | self.height = height 24 | centerY = (height + margin) / 2 25 | scaleFactor = Float(height) / 4.0 26 | } 27 | 28 | func plot(_ audioBuffer: UnsafeBufferPointer) { 29 | let samplesPerPixel = audioBuffer.count / width 30 | 31 | var sampleCounter = 0 32 | var averageCounter = 0 33 | var average: Float = 0 34 | 35 | CanvasType.beginPath(ctx: contextIndex) 36 | CanvasType.moveTo(ctx: contextIndex, x: 0, y: centerY) 37 | for sample in audioBuffer { 38 | average += sample 39 | 40 | if sampleCounter < samplesPerPixel { 41 | sampleCounter += 1 42 | average += sample 43 | } else { 44 | CanvasType.lineTo( 45 | ctx: contextIndex, 46 | x: averageCounter, 47 | y: centerY + Int(average * scaleFactor / Float(samplesPerPixel)) 48 | ) 49 | 50 | averageCounter += 1 51 | average = 0 52 | sampleCounter = 0 53 | } 54 | } 55 | 56 | if average != 0 { 57 | CanvasType.lineTo( 58 | ctx: contextIndex, 59 | x: averageCounter, 60 | y: centerY + Int(average * scaleFactor / Float(sampleCounter)) 61 | ) 62 | } 63 | 64 | CanvasType.stroke(ctx: contextIndex) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Guest/Sources/Plotter/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | @_expose(wasm, "allocateAudioBuffer") 14 | func allocateAudioBuffer(byteCount: Int) -> UnsafeRawPointer { 15 | let buffer = UnsafeMutableRawBufferPointer.allocate( 16 | byteCount: byteCount, 17 | alignment: MemoryLayout.alignment 18 | ) 19 | 20 | return .init(buffer.baseAddress!) 21 | } 22 | 23 | @_expose(wasm, "free") 24 | func free(pointer: UnsafeMutableRawPointer) { 25 | pointer.deallocate() 26 | } 27 | 28 | @_expose(wasm, "plot") 29 | func plot( 30 | contextIndex: Int, 31 | width: Int, 32 | height: Int, 33 | margin: Int, 34 | start: UnsafeRawPointer, 35 | byteCount: Int 36 | ) { 37 | let plotter = Plotter( 38 | contextIndex: contextIndex, 39 | width: width, 40 | height: height, 41 | margin: margin 42 | ) 43 | let samplesCount = byteCount / MemoryLayout.stride 44 | let buffer = UnsafeBufferPointer( 45 | start: start.assumingMemoryBound(to: Float.self), 46 | count: samplesCount 47 | ) 48 | 49 | plotter.plot(buffer) 50 | } 51 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/AudioBuffer.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | /// A non-copyable buffer of audio samples. 14 | struct AudioBuffer: ~Copyable { 15 | let storage: UnsafeMutableBufferPointer 16 | 17 | /// Allocates an audio buffer and fills it with samples from a given signal. 18 | /// - Parameter capacity: the number of samples 19 | init(capacity: Int, source: inout some Signal) { 20 | self.storage = .allocate(capacity: capacity) 21 | 22 | for i in self.storage.indices { 23 | let sample = source.next() 24 | self.storage[i] = sample 25 | } 26 | } 27 | 28 | deinit { 29 | self.storage.deallocate() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/AudioEncode.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | @_extern(wasm, module: "audio", name: "encode") 14 | @_extern(c) 15 | private func encodeAudio(ctx: Int, address: Int, byteCount: Int) 16 | 17 | enum Audio { 18 | static func encode(contextIndex: Int, _ buffer: borrowing AudioBuffer) { 19 | buffer.storage.withContiguousStorageIfAvailable { 20 | encodeAudio( 21 | ctx: contextIndex, 22 | address: Int(bitPattern: $0.baseAddress!), 23 | byteCount: MemoryLayout.stride * $0.count 24 | ) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/DOMInterop.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | @_extern(wasm, module: "console", name: "log") 14 | @_extern(c) 15 | private func consoleLog(ctx: Int, address: Int, byteCount: Int) 16 | 17 | @_extern(wasm, module: "console", name: "logInt") 18 | @_extern(c) 19 | func consoleLogInt(_ int: Int) 20 | 21 | @_extern(wasm, module: "console", name: "logFloat") 22 | @_extern(c) 23 | func consoleLogFloat(_ float: Float) 24 | 25 | enum Console { 26 | static func log(contextIndex: Int, string: StaticString) { 27 | consoleLog( 28 | ctx: contextIndex, 29 | address: Int(bitPattern: string.utf8Start), 30 | byteCount: string.utf8CodeUnitCount 31 | ) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/Effects/LadderFilter.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import VultDSP 14 | 15 | struct LadderFilter: Signal { 16 | var source: Source 17 | 18 | var cutoff: Float = 0 19 | var resonance: Float = 0.0 20 | 21 | var state = Ladder__ctx_type_4() 22 | 23 | mutating func next() -> Float { 24 | Ladder_heun(&self.state, self.source.next(), self.cutoff, self.resonance) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/Instruments/Bass.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | struct Bass: SequencedInstrument { 14 | var currentStep: SequencerStep = .noteOff { 15 | didSet { 16 | switch self.currentStep { 17 | case .noteOff: 18 | self.core.modulation.isNoteOn = false 19 | case .noteOn(let pitch): 20 | self.core.source.pitch = pitch 21 | self.core.modulation.isNoteOn = true 22 | } 23 | } 24 | } 25 | 26 | var core = Modulator( 27 | source: Triangle(pitch: .g), 28 | modulation: AttackHoldRelease(), 29 | sourceUpdate: { signal, amplitude in 30 | signal.amplitude = amplitude 31 | } 32 | ) 33 | 34 | mutating func next() -> Float { 35 | self.core.next() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/Instruments/Drums.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import VultDSP 14 | 15 | struct Noise: Signal { 16 | var state = Noise__ctx_type_1() 17 | var amplitude: Float = 1.0 18 | 19 | mutating func next() -> Float { 20 | Noise_process(&self.state, 1.0) * self.amplitude 21 | } 22 | } 23 | 24 | struct HiHat: SequencedInstrument { 25 | var currentStep: SequencerStep = .noteOff { 26 | didSet { 27 | switch self.currentStep { 28 | case .noteOff: 29 | self.core.modulation.isNoteOn = false 30 | case .noteOn: 31 | self.core.modulation.isNoteOn = true 32 | } 33 | } 34 | } 35 | 36 | var core = Modulator( 37 | source: Noise(), 38 | modulation: AttackHoldRelease(attack: 0.01, hold: 0.01, release: 0.2), 39 | sourceUpdate: { triangle, amplitude in 40 | triangle.amplitude = amplitude 41 | } 42 | ) 43 | 44 | mutating func next() -> Float { 45 | self.core.next() 46 | } 47 | } 48 | 49 | struct Kick: SequencedInstrument { 50 | var state = Kick__ctx_type_1() 51 | 52 | var currentStep: SequencerStep = .noteOn(.e) { 53 | didSet { 54 | switch self.currentStep { 55 | case .noteOn(let pitch): 56 | Kick_controlChange(&state, 31, Int32(pitch.rawValue * 10), 0) 57 | case .noteOff: 58 | break 59 | } 60 | } 61 | } 62 | 63 | mutating func next() -> Float { 64 | switch self.currentStep { 65 | case .noteOff: 66 | Kick_process(&self.state, 0) 67 | case .noteOn: 68 | Kick_process(&self.state, 1) 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/Instruments/Sequencer.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | enum SequencerStep { 14 | case noteOff 15 | case noteOn(Pitch) 16 | } 17 | 18 | protocol SequencedInstrument: Signal { 19 | var currentStep: SequencerStep { get set } 20 | } 21 | 22 | struct Sequencer: Signal { 23 | var instrument: Instrument 24 | 25 | let sequence: [SequencerStep] 26 | 27 | let stepLengthInSeconds: Float 28 | 29 | var currentSample = 0 30 | 31 | mutating func next() -> Float { 32 | let stepLengthInSamples = Int(stepLengthInSeconds * Float(sampleRate)) 33 | var currentStepIndex = self.currentSample / stepLengthInSamples 34 | 35 | if currentStepIndex >= self.sequence.count { 36 | self.currentSample = self.currentSample % stepLengthInSamples 37 | currentStepIndex = 0 38 | } 39 | 40 | self.instrument.currentStep = self.sequence[currentStepIndex] 41 | self.currentSample += 1 42 | 43 | return self.instrument.next() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/Mixer.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | struct Mixer: Signal { 14 | var source1: Source1 15 | var volume1: Float = 1.0 16 | 17 | var source2: Source2 18 | var volume2: Float = 1.0 19 | 20 | var source3: Source3 21 | var volume3: Float = 1.0 22 | 23 | mutating func next() -> Float { 24 | self.source1.next() * self.volume1 + self.source2.next() * self.volume2 + self.source3.next() * self.volume3 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/MusicTheory/Pitch.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | // Equal temperament ratios: https://en.wikipedia.org/wiki/Equal_temperament#Comparison_with_just_intonation 14 | struct Pitch { 15 | var rawValue: Float 16 | 17 | func octave(_ octaveShift: Int) -> Pitch { 18 | Pitch(rawValue: rawValue + Float(octaveShift)) 19 | } 20 | 21 | static let c = Pitch(rawValue: 0) 22 | static let dFlat = Pitch(rawValue: 0.059463) 23 | static let d = Pitch(rawValue: 0.122462) 24 | static let eFlat = Pitch(rawValue: 0.189207) 25 | static let e = Pitch(rawValue: 0.259921) 26 | static let f = Pitch(rawValue: 0.33484) 27 | static let gFlat = Pitch(rawValue: 0.414214) 28 | static let g = Pitch(rawValue: 0.498307) 29 | static let aFlat = Pitch(rawValue: 0.587401) 30 | static let a = Pitch(rawValue: 0.681793) 31 | static let bFlat = Pitch(rawValue: 0.781797) 32 | static let b = Pitch(rawValue: 0.887749) 33 | } 34 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/Utilities/AttackHoldRelease.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import VultDSP 14 | 15 | struct AttackHoldRelease: Signal { 16 | var state = Ahr__ctx_type_0() 17 | 18 | var attack: Float = 0.0 19 | var hold: Float = 0.5 20 | var release: Float = 0.5 21 | 22 | var isNoteOn = false 23 | 24 | mutating func next() -> Float { 25 | Ahr_do(&self.state, self.isNoteOn ? 1 : 0, self.attack, self.hold, self.release) 26 | return Ahr_do_ret_0(&self.state) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/Utilities/Modulator.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | struct Modulator: Signal { 14 | var source: Source 15 | var modulation: Modulation 16 | 17 | var sourceUpdate: (inout Source, Float) -> () 18 | 19 | mutating func next() -> Float { 20 | self.sourceUpdate(&self.source, self.modulation.next()) 21 | return self.source.next() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/Waveforms/Saw.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | /// Number of samples generated per second. 14 | let sampleRate = 44_100 15 | 16 | /// Stateless sawtooth-shaped waveform function. 17 | /// - Parameters: 18 | /// - time: Number of seconds passed since the current oscillation started. 19 | /// - frequency: Frequency of oscillation, in hertz. 20 | /// - Returns: An audio sample in the normalized range of -1.0...1.0 21 | func saw(time: Float, frequency: Float) -> Float { 22 | let phase = time * frequency 23 | 24 | return 2 * (phase - (0.5 + phase).rounded(.down)) 25 | } 26 | 27 | /// Stateful sawtooth-shaped signal. 28 | struct Saw: Signal { 29 | /// Frequency of oscillation, in hertz. 30 | var frequency: Float = 440.0 31 | 32 | /// The "volume" of the signal, i.e. the absolute boundary of the range in 33 | /// which this signal oscillates. Default amplitude of 1.0 means that 34 | /// samples returned from ``Saw/next()`` will always stay in `-1.0...1.0` range. 35 | var amplitude: Float = 1.0 36 | 37 | /// Number of seconds passed since the current oscillation started. To avoid 38 | /// overflowing, this value is reset to 0.0 after every oscillation. 39 | var currentTime: Float = 0.0 40 | 41 | mutating func next() -> Float { 42 | let result = saw(time: currentTime, frequency: frequency) 43 | 44 | currentTime += 1.0 / Float(sampleRate) 45 | if currentTime > 1.0 / frequency { 46 | currentTime = 0 47 | } 48 | 49 | return result * amplitude 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/Waveforms/Signal.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | /// An abstract digital signal that produces an infinite amount of samples. 14 | protocol Signal { 15 | /// Updates current state of the signal and produces the next sample. 16 | /// - Returns: The latest sample in this signal. 17 | mutating func next() -> Float 18 | } 19 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/Waveforms/Square.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | /// Stateful square-shaped waveform. For values of ``Square/pulseWidth`` other than the default 0.5, strictly speaking 14 | /// it produces a rectangular-shaped waveform. 15 | struct Square: Signal { 16 | /// Frequency of oscillations in hertz. 17 | var frequency: Float { 18 | didSet { 19 | self.saw.frequency = self.frequency 20 | } 21 | } 22 | 23 | /// The "volume" of the signal, i.e. the absolute boundary of the range in which this signal oscillates. Default 24 | /// amplitude of 1.0 means that samples returned from ``Square/next()`` will always stay in `-1.0...1.0` range. 25 | var amplitude: Float 26 | 27 | /// The ratio of a width of a pulse in this waveform in the range of `0.0..<1.0`. The default value of 0.5 makes 28 | /// the pulse look like a square. Values smaller than 0.5 will make it more narrow, values larger than 0.5 make it 29 | /// wider. 30 | var pulseWidth: Float 31 | 32 | /// The underlying saw-shaped waveform used as a helper to compute samples. 33 | private var saw: Saw 34 | 35 | init( 36 | frequency: Float = 440.0, 37 | amplitude: Float = 1.0, 38 | pulseWidth: Float = 0.5 39 | ) { 40 | self.frequency = frequency 41 | self.amplitude = amplitude 42 | self.pulseWidth = pulseWidth 43 | self.saw = Saw(frequency: frequency, amplitude: amplitude) 44 | } 45 | 46 | mutating func next() -> Float { 47 | if abs(self.saw.next()) > pulseWidth { 48 | amplitude 49 | } else { 50 | -amplitude 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Guest/Sources/Shared/Waveforms/Triangle.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import VultDSP 14 | 15 | /// Stateful triangle-shaped waveform. 16 | struct Triangle: Signal { 17 | /// The pitch parameter of the waveform that sets its tone. 18 | var pitch: Pitch 19 | 20 | /// The "volume" of the signal, i.e. the absolute boundary of the range in which this signal oscillates. Default 21 | /// amplitude of 1.0 means that samples returned from ``Triangle/next()`` will always stay in `-1.0...1.0` range. 22 | var amplitude: Float = 1.0 23 | 24 | /// The state managed by the underlying VultDSP implementation of the signal. 25 | var state = Triangle__ctx_type_0() 26 | 27 | mutating func next() -> Float { 28 | Triangle_process(&self.state, self.pitch.rawValue / 10.0, 0, 0) * self.amplitude 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/VultLibrary/phase.vult: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2017 Leonardo Laguna Ruiz 5 | ----- 6 | Produces an unipolar aliased saw wave. 7 | 8 | */ 9 | 10 | fun process(cv:real, reset:real) : real { 11 | mem rate; 12 | if(Util.change(cv)) 13 | { 14 | rate = Util.cvToRate_1024(cv); 15 | } 16 | mem phase = if Util.edge(reset > 0.5) then 0.0 else phase + rate; 17 | phase = if phase > 1024.0 then phase - 1024.0 else phase; 18 | return phase / 1024.0; 19 | } 20 | and noteOn(note:int,velocity:int,channel:int){ } 21 | and noteOff(note:int,channel:int){ } 22 | and controlChange(control:int,value:int,channel:int){ } 23 | and default()@[init] { 24 | rate = Util.cvToRate_1024(0.0); 25 | } 26 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/VultLibrary/tables.vult: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2017 Leonardo Laguna Ruiz 5 | ----- 6 | Tables of different functions 7 | */ 8 | 9 | 10 | // Normalized sine table 11 | fun nsine(x) @[table(size=128,min=0.0,max=1.0)] { 12 | return sin(6.283185307179586 * x); 13 | } 14 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/VultLibrary/util.vult: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2017 Leonardo Laguna Ruiz 5 | ----- 6 | Collection of small useful functions 7 | */ 8 | 9 | fun edge(x:bool) : bool { 10 | mem pre; 11 | val ret = x && not(pre); 12 | pre = x; 13 | return ret; 14 | } 15 | 16 | fun change(x:real):bool { 17 | mem pre_x; 18 | val v:bool = pre_x <> x; 19 | pre_x = x; 20 | return v; 21 | } 22 | 23 | fun map(x:real,x0,x1,y0,y1) : real { 24 | return (x-x0)*(y1-y0)/(x1-x0) + y0; 25 | } 26 | 27 | fun dcblock(x0){ 28 | mem x1,y1; 29 | val y0 = x0-x1+y1*0.995; 30 | x1,y1 = x0,y0; 31 | return y0; 32 | } 33 | 34 | fun smooth(input){ 35 | mem x; 36 | x = x+(input-x)*0.005; 37 | return x; 38 | } 39 | 40 | fun average2(x1:real) : real { 41 | mem x0; 42 | val result = (x0 + x1) / 2.0; 43 | x0 = x1; 44 | return result; 45 | } 46 | 47 | fun cubic_clipper(x) { 48 | if(x <= -2.0/3.0) 49 | return -2.0/3.0; 50 | else if(x >= 2.0/3.0) 51 | return 2.0/3.0; 52 | else 53 | return x - (x * x * x) / 3.0; 54 | } 55 | 56 | /* Rate to get a 2^10 ramp */ 57 | fun pitchToRate_1024(pitch) @[table(size=32,min=0.0,max=127.0)] { 58 | // 2^10 /44100 440 2^((pitch - 69)/12.) 59 | return 0.18984168003671556 * exp(0.057762265046662105 * pitch); 60 | } 61 | 62 | fun pitchToRate(pitch) @[table(size=32, min=0.0, max=127.0)] { 63 | // 1.0 /44100 440 2^((pitch - 69)/12.) 64 | return 0.00018539226566085504 * exp(0.057762265046662105 * pitch); 65 | } 66 | 67 | fun cvToPitch(cv) { 68 | return cv * 120.0 + 24.0; 69 | } 70 | 71 | fun cvToRate_1024(cv) @[table(size=32,min=0.0,max=0.9)] { 72 | return pitchToRate_1024(cvToPitch(cv)); 73 | } 74 | 75 | fun cvToRate(cv) @[table(size=128, min=0.0, max=0.9)] { 76 | return pitchToRate(cvToPitch(cv)); 77 | } 78 | 79 | fun pitchToCv(pitch) { 80 | return 1.0/120.0 * (-24.0 + pitch); 81 | } 82 | 83 | fun cvToperiod(cv) @[table(size=32,min=0.0,max=1.0)] { 84 | val pitch = Util.cvToPitch(cv); 85 | val f = 8.175798915643707 * exp(0.057762265046662105 * pitch); //440. 2^((pitch - 69)/12.) 86 | return 44100.0 / f / 2.0; 87 | } 88 | 89 | /* Returns the frequency in kHz of the corresponding CV */ 90 | fun cvTokHz(cv) @[table(size=32,min=0.0,max=1.0)] { 91 | val pitch = Util.cvToPitch(cv); 92 | val f = 8.175798915643707 * exp(0.057762265046662105 * pitch); //440. 2^((pitch - 69)/12.) 93 | return f/1000.0; 94 | } 95 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/ahr.vult: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2017 Leonardo Laguna Ruiz 5 | ----- 6 | Attack Hold Release Envelope. 7 | 8 | To pass the parameters as direct values use the function 'do'. 9 | For parameters as controls use 'process'. 10 | */ 11 | 12 | fun do(gate:real, a:real, h:real, r:real) { 13 | mem state; 14 | mem out; 15 | mem rate; 16 | mem target; 17 | mem hold_phase; 18 | 19 | val release = 0; 20 | val attack = 1; 21 | val hold = 2; 22 | val reset = 3; 23 | 24 | val bgate = gate > 0.0; 25 | 26 | if(Util.edge(bgate)) { 27 | state = reset; 28 | } 29 | 30 | val resetting = if state == reset then 1.0 else 0.0; 31 | 32 | // transitions 33 | 34 | if(Util.edge(out > 1024.0)) { 35 | hold_phase = 0.0; 36 | state = hold; 37 | } 38 | if(out < 10.0 && state == reset) { 39 | state = attack; 40 | } 41 | if(hold_phase > 100.0 && state == hold) { 42 | state = release; 43 | } 44 | 45 | // states 46 | 47 | if(state == reset) { 48 | rate = 1.0 / (100.0 * 0.01 + 0.01); 49 | target = 0.0; 50 | } 51 | if(state == attack) { 52 | rate = 1.0 / (100.0 * a + 0.01); 53 | target = 1.2 * 1024.0; 54 | } 55 | if(state == hold) { 56 | val hrate = 1.0 / (100.0 * h + 0.01); 57 | hold_phase = hold_phase + hrate; 58 | } 59 | if(state == release) { 60 | rate = 1.0 / (100.0 * r + 0.01); 61 | target = 0.0; 62 | } 63 | 64 | out = out + (target - out) * rate * 0.005; 65 | 66 | 67 | return clip(out/1024.0,0.0,1.0), resetting; 68 | } 69 | 70 | fun process(gate:real) { 71 | mem knob1, knob2, knob3; 72 | 73 | return do(gate,knob1,knob2,knob3); 74 | } 75 | and noteOn(note:int, velocity:int, channel:int) { 76 | } 77 | and noteOff(note:int, channel:int) { 78 | } 79 | and controlChange(control:int, value: int, channel:int) { 80 | if(control == 1) 81 | knob1 = real(value)/127.0; 82 | if(control == 2) 83 | knob2 = real(value)/127.0; 84 | if(control == 3) 85 | knob3 = real(value)/127.0; 86 | } 87 | and default() { 88 | knob1 = 0.0; 89 | knob2 = 0.5; 90 | knob3 = 0.5; 91 | } 92 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/include/waveforms.h: -------------------------------------------------------------------------------- 1 | #include "../out.h" 2 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/kick.vult: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2017 Leonardo Laguna Ruiz 5 | */ 6 | 7 | // Drum synth in the 909 kick style 8 | fun do(gate, odecay, pitch, swept, noise) { 9 | // Envelope of the drum. One parameter affects the hold and relase 10 | val osc_env, env_reset = Ahr.do(gate, 0.005, 0.1 + odecay ,odecay+0.01); 11 | // Change of pitch 12 | val cv = Swept.process(1.0-env_reset, pitch + swept*0.4, pitch, 0.1); 13 | // Main triangle oscillator 14 | // Note: the oscillator is dissabled while the nevelop resets 15 | val osc = Triangle.process(cv, 0.0, env_reset); 16 | // Saturates the triangle to get a sine with some harmonics 17 | val osc_sat = Saturate.process(1.5 * osc); 18 | 19 | val noise_env, _ = Ahr.do(gate, 0.001, 0.01, noise * 0.01+0.001); 20 | val noise_osc = noise * Noise.process(1.0) / 3.0; 21 | 22 | return osc_env * osc_sat + noise_env * noise_osc; 23 | } 24 | 25 | 26 | fun process(gate) { 27 | mem odecay, pitch, swept, noise; 28 | return do(gate, odecay, pitch, swept, noise); 29 | } 30 | 31 | and noteOn(note:int,velocity:int,channel:int){ } 32 | and noteOff(note:int,channel:int){ } 33 | and controlChange(control:int,value:int,channel:int) { 34 | if(control == 30) odecay = real(value)/127.0; 35 | if(control == 31) pitch = Util.map(real(value), 0.0, 127.0, 0.0, 0.1); 36 | if(control == 32) swept = real(value)/127.0; 37 | if(control == 33) noise = real(value)/127.0; 38 | } 39 | and default(){ } 40 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/ladder.vult: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2017 Leonardo Laguna Ruiz 5 | ----- 6 | Diode ladder filter 7 | */ 8 | 9 | fun tune(cut) @[table(min = 0.0, max = 1.0, size = 128)]{ 10 | val f = Util.cvTokHz(cut); 11 | f = clip(f, 0.0, 20.0); 12 | val fh = (2.0 * pi()) * f / (4.0 * 44.1); 13 | return fh; 14 | } 15 | 16 | fun heun(input, fh, res) { 17 | mem p0, p1, p2, p3; 18 | 19 | val wt0 = Util.cubic_clipper(input - 4.0 * res * p3); 20 | val wt1 = Util.cubic_clipper(p0); 21 | val dpt0 = (wt0 - wt1) * fh; 22 | val wt3 = Util.cubic_clipper(p1); 23 | val dpt1 = (wt1 - wt3) * fh; 24 | val wt5 = Util.cubic_clipper(p2); 25 | val dpt2 = (wt3 - wt5) * fh; 26 | val wt7 = Util.cubic_clipper(p3); 27 | val dpt3 = (wt5 - wt7) * fh; 28 | 29 | val pt0 = p0 + dpt0; 30 | val pt1 = p1 + dpt1; 31 | val pt2 = p2 + dpt2; 32 | val pt3 = p3 + dpt3; 33 | 34 | val w0 = Util.cubic_clipper(input - 4.0 * res * pt3); 35 | val w1 = Util.cubic_clipper(pt0); 36 | val dp0 = (w0 - w1) * fh; 37 | val w3 = Util.cubic_clipper(pt1); 38 | val dp1 = (w1 - w3) * fh; 39 | val w5 = Util.cubic_clipper(pt2); 40 | val dp2 = (w3 - w5) * fh; 41 | val w7 = Util.cubic_clipper(pt3); 42 | val dp3 = (w5 - w7) * fh; 43 | 44 | p0 = p0 + (dp0 + dpt0)/ 2.0; 45 | p1 = p1 + (dp1 + dpt1)/ 2.0; 46 | p2 = p2 + (dp2 + dpt2)/ 2.0; 47 | p3 = p3 + (dp3 + dpt3)/ 2.0; 48 | 49 | return p3; 50 | } 51 | 52 | fun euler(input, fh, res) { 53 | mem p0, p1, p2, p3; 54 | val w0 = Util.cubic_clipper(input - 4.0 * res * p3); 55 | val w1 = Util.cubic_clipper(p0); 56 | val dpt0 = (w0 - w1) * fh; 57 | val w3 = Util.cubic_clipper(p1); 58 | val dpt1 = (w1 - w3) * fh; 59 | val w5 = Util.cubic_clipper(p2); 60 | val dpt2 = (w3 - w5) * fh; 61 | val w7 = Util.cubic_clipper(p3); 62 | val dpt3 = (w5 - w7) * fh; 63 | p0 = p0 + dpt0; 64 | p1 = p1 + dpt1; 65 | p2 = p2 + dpt2; 66 | p3 = p3 + dpt3; 67 | return p3; 68 | } 69 | 70 | fun process_euler(input:real, cut:real, res:real):real{ 71 | mem fh; 72 | if(Util.change(cut)) { 73 | fh = tune(cut); 74 | } 75 | _ = e:euler(input, fh, res); 76 | _ = e:euler(input, fh, res); 77 | _ = e:euler(input, fh, res); 78 | val out = e:euler(input, fh, res); 79 | return out; 80 | } 81 | 82 | fun process_heun(input:real, cut:real, res:real):real{ 83 | mem fh; 84 | if(Util.change(cut)) { 85 | fh = tune(cut); 86 | } 87 | _ = h:heun(input, fh, res); 88 | _ = h:heun(input, fh, res); 89 | _ = h:heun(input, fh, res); 90 | val out = h:heun(input, fh, res); 91 | return out; 92 | } 93 | 94 | fun process(input:real, cut:real, res:real):real{ 95 | return process_heun(input, cut, res); 96 | } 97 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/noise.vult: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2017 Leonardo Laguna Ruiz 5 | ----- 6 | Simple noise generator 7 | */ 8 | 9 | fun pink(x:real){ 10 | mem w1; 11 | val b0 = 0.02771298631913731; 12 | val b1 = 0.02771298631913731; 13 | val a1 = -0.9445740273617255; 14 | val w0 = x - a1*w1; 15 | val y0 = b0*w0 + b1*w1; 16 | w1 = w0; 17 | return y0; 18 | } 19 | 20 | fun process(color) { 21 | mem x1 = (x1 * 17389 + 7919) % 32768; 22 | val y1 = real(x1)/32768.0; 23 | mem x2 = (x2 * 27449 + 12553) % 32768; 24 | val y2 = real(x2)/32768.0; 25 | val out = if color>0.5 then pink(y1-y2) else y1-y2; 26 | return 2.0*out; 27 | } 28 | and noteOn(note:int,velocity:int,channel:int){ } 29 | and noteOff(note:int,channel:int){ } 30 | and controlChange(control:int,value:int,channel:int){ } 31 | and default(){ } 32 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/out.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* Code automatically generated by Vult https://github.com/modlfo/vult */ 3 | #include "out.h" 4 | 5 | float Noise_pink(Noise__ctx_type_0 &_ctx, float x){ 6 | float b0; 7 | b0 = 0.0277129863191f; 8 | float b1; 9 | b1 = 0.0277129863191f; 10 | float a1; 11 | a1 = -0.944574027362f; 12 | float w0; 13 | w0 = (x + (- (_ctx.w1 * a1))); 14 | float y0; 15 | y0 = ((_ctx.w1 * b1) + (b0 * w0)); 16 | _ctx.w1 = w0; 17 | return y0; 18 | } 19 | 20 | void Noise__ctx_type_1_init(Noise__ctx_type_1 &_output_){ 21 | Noise__ctx_type_1 _ctx; 22 | _ctx.x2 = 0; 23 | _ctx.x1 = 0; 24 | Noise__ctx_type_0_init(_ctx._inst1cc); 25 | _output_ = _ctx; 26 | return ; 27 | } 28 | 29 | float Noise_process(Noise__ctx_type_1 &_ctx, float color){ 30 | _ctx.x1 = ((7919 + (17389 * _ctx.x1)) % 32768); 31 | float y1; 32 | y1 = (3.0517578125e-05f * int_to_float(_ctx.x1)); 33 | _ctx.x2 = ((12553 + (27449 * _ctx.x2)) % 32768); 34 | float y2; 35 | y2 = (3.0517578125e-05f * int_to_float(_ctx.x2)); 36 | float out; 37 | if(color > 0.5f){ 38 | out = Noise_pink(_ctx._inst1cc,(y1 + (- y2))); 39 | } 40 | else 41 | { 42 | out = (y1 + (- y2)); 43 | } 44 | return (2.f * out); 45 | } 46 | 47 | void Util__ctx_type_3_init(Util__ctx_type_3 &_output_){ 48 | Util__ctx_type_3 _ctx; 49 | _ctx.y1 = 0.0f; 50 | _ctx.x1 = 0.0f; 51 | _output_ = _ctx; 52 | return ; 53 | } 54 | 55 | float Util_dcblock(Util__ctx_type_3 &_ctx, float x0){ 56 | float y0; 57 | y0 = (x0 + (- _ctx.x1) + (0.995f * _ctx.y1)); 58 | _ctx.x1 = x0; 59 | _ctx.y1 = y0; 60 | return y0; 61 | } 62 | 63 | void Ladder__ctx_type_4_init(Ladder__ctx_type_4 &_output_){ 64 | Ladder__ctx_type_4 _ctx; 65 | _ctx.p3 = 0.0f; 66 | _ctx.p2 = 0.0f; 67 | _ctx.p1 = 0.0f; 68 | _ctx.p0 = 0.0f; 69 | _output_ = _ctx; 70 | return ; 71 | } 72 | 73 | float Ladder_heun(Ladder__ctx_type_4 &_ctx, float input, float fh, float res){ 74 | float wt0; 75 | wt0 = Util_cubic_clipper((input + (-4.f * _ctx.p3 * res))); 76 | float wt1; 77 | wt1 = Util_cubic_clipper(_ctx.p0); 78 | float dpt0; 79 | dpt0 = (fh * (wt0 + (- wt1))); 80 | float wt3; 81 | wt3 = Util_cubic_clipper(_ctx.p1); 82 | float dpt1; 83 | dpt1 = (fh * (wt1 + (- wt3))); 84 | float wt5; 85 | wt5 = Util_cubic_clipper(_ctx.p2); 86 | float dpt2; 87 | dpt2 = (fh * (wt3 + (- wt5))); 88 | float wt7; 89 | wt7 = Util_cubic_clipper(_ctx.p3); 90 | float dpt3; 91 | dpt3 = (fh * (wt5 + (- wt7))); 92 | float pt0; 93 | pt0 = (_ctx.p0 + dpt0); 94 | float pt1; 95 | pt1 = (_ctx.p1 + dpt1); 96 | float pt2; 97 | pt2 = (_ctx.p2 + dpt2); 98 | float pt3; 99 | pt3 = (_ctx.p3 + dpt3); 100 | float w0; 101 | w0 = Util_cubic_clipper((input + (-4.f * pt3 * res))); 102 | float w1; 103 | w1 = Util_cubic_clipper(pt0); 104 | float dp0; 105 | dp0 = (fh * (w0 + (- w1))); 106 | float w3; 107 | w3 = Util_cubic_clipper(pt1); 108 | float dp1; 109 | dp1 = (fh * (w1 + (- w3))); 110 | float w5; 111 | w5 = Util_cubic_clipper(pt2); 112 | float dp2; 113 | dp2 = (fh * (w3 + (- w5))); 114 | float w7; 115 | w7 = Util_cubic_clipper(pt3); 116 | float dp3; 117 | dp3 = (fh * (w5 + (- w7))); 118 | _ctx.p0 = (_ctx.p0 + (0.5f * (dp0 + dpt0))); 119 | _ctx.p1 = (_ctx.p1 + (0.5f * (dp1 + dpt1))); 120 | _ctx.p2 = (_ctx.p2 + (0.5f * (dp2 + dpt2))); 121 | _ctx.p3 = (_ctx.p3 + (0.5f * (dp3 + dpt3))); 122 | return _ctx.p3; 123 | } 124 | 125 | void Ladder__ctx_type_5_init(Ladder__ctx_type_5 &_output_){ 126 | Ladder__ctx_type_5 _ctx; 127 | _ctx.p3 = 0.0f; 128 | _ctx.p2 = 0.0f; 129 | _ctx.p1 = 0.0f; 130 | _ctx.p0 = 0.0f; 131 | _output_ = _ctx; 132 | return ; 133 | } 134 | 135 | float Ladder_euler(Ladder__ctx_type_5 &_ctx, float input, float fh, float res){ 136 | float w0; 137 | w0 = Util_cubic_clipper((input + (-4.f * _ctx.p3 * res))); 138 | float w1; 139 | w1 = Util_cubic_clipper(_ctx.p0); 140 | float dpt0; 141 | dpt0 = (fh * (w0 + (- w1))); 142 | float w3; 143 | w3 = Util_cubic_clipper(_ctx.p1); 144 | float dpt1; 145 | dpt1 = (fh * (w1 + (- w3))); 146 | float w5; 147 | w5 = Util_cubic_clipper(_ctx.p2); 148 | float dpt2; 149 | dpt2 = (fh * (w3 + (- w5))); 150 | float w7; 151 | w7 = Util_cubic_clipper(_ctx.p3); 152 | float dpt3; 153 | dpt3 = (fh * (w5 + (- w7))); 154 | _ctx.p0 = (_ctx.p0 + dpt0); 155 | _ctx.p1 = (_ctx.p1 + dpt1); 156 | _ctx.p2 = (_ctx.p2 + dpt2); 157 | _ctx.p3 = (_ctx.p3 + dpt3); 158 | return _ctx.p3; 159 | } 160 | 161 | void Ladder__ctx_type_6_init(Ladder__ctx_type_6 &_output_){ 162 | Ladder__ctx_type_6 _ctx; 163 | _ctx.fh = 0.0f; 164 | Ladder__ctx_type_5_init(_ctx.e); 165 | Util__ctx_type_1_init(_ctx._inst13b); 166 | _output_ = _ctx; 167 | return ; 168 | } 169 | 170 | float Ladder_process_euler(Ladder__ctx_type_6 &_ctx, float input, float cut, float res){ 171 | if(Util_change(_ctx._inst13b,cut)){ 172 | _ctx.fh = Ladder_tune(cut); 173 | } 174 | Ladder_euler(_ctx.e,input,_ctx.fh,res); 175 | Ladder_euler(_ctx.e,input,_ctx.fh,res); 176 | Ladder_euler(_ctx.e,input,_ctx.fh,res); 177 | float out; 178 | out = Ladder_euler(_ctx.e,input,_ctx.fh,res); 179 | return out; 180 | } 181 | 182 | void Ladder__ctx_type_7_init(Ladder__ctx_type_7 &_output_){ 183 | Ladder__ctx_type_7 _ctx; 184 | Ladder__ctx_type_4_init(_ctx.h); 185 | _ctx.fh = 0.0f; 186 | Util__ctx_type_1_init(_ctx._inst13b); 187 | _output_ = _ctx; 188 | return ; 189 | } 190 | 191 | float Ladder_process_heun(Ladder__ctx_type_7 &_ctx, float input, float cut, float res){ 192 | if(Util_change(_ctx._inst13b,cut)){ 193 | _ctx.fh = Ladder_tune(cut); 194 | } 195 | Ladder_heun(_ctx.h,input,_ctx.fh,res); 196 | Ladder_heun(_ctx.h,input,_ctx.fh,res); 197 | Ladder_heun(_ctx.h,input,_ctx.fh,res); 198 | float out; 199 | out = Ladder_heun(_ctx.h,input,_ctx.fh,res); 200 | return out; 201 | } 202 | 203 | void Triangle__ctx_type_0_init(Triangle__ctx_type_0 &_output_){ 204 | Triangle__ctx_type_0 _ctx; 205 | _ctx.reset_state = false; 206 | _ctx.reset_phase = 0.0f; 207 | _ctx.rate = 0.0f; 208 | _ctx.phase = 0.0f; 209 | _ctx.direction = false; 210 | Util__ctx_type_0_init(_ctx._inst451); 211 | Util__ctx_type_0_init(_ctx._inst351); 212 | Util__ctx_type_1_init(_ctx._inst13b); 213 | Triangle_default(_ctx); 214 | _output_ = _ctx; 215 | return ; 216 | } 217 | 218 | float Triangle_process(Triangle__ctx_type_0 &_ctx, float cv, float reset, float disable){ 219 | float out; 220 | out = 0.0f; 221 | if(Util_change(_ctx._inst13b,cv)){ 222 | _ctx.rate = (4.f * Util_cvToRate_1024(cv)); 223 | } 224 | float new_phase; 225 | float _if_13; 226 | if(_ctx.direction){ 227 | _if_13 = _ctx.rate; 228 | } 229 | else 230 | { 231 | _if_13 = (- _ctx.rate); 232 | } 233 | new_phase = (_ctx.phase + _if_13); 234 | uint8_t bdisable; 235 | bdisable = (disable > 0.5f); 236 | if(Util_edge(_ctx._inst351,(reset > 0.0f)) || Util_edge(_ctx._inst451,bdisable)){ 237 | _ctx.reset_phase = _ctx.phase; 238 | _ctx.reset_state = true; 239 | new_phase = 0.0f; 240 | } 241 | if(new_phase > 1024.f){ 242 | new_phase = (1024.f + (- (-1024.f + new_phase))); 243 | _ctx.direction = false; 244 | } 245 | else 246 | { 247 | if(new_phase < -1024.f){ 248 | _ctx.direction = true; 249 | } 250 | } 251 | if(bdisable){ 252 | _ctx.phase = 0.0f; 253 | } 254 | else 255 | { 256 | _ctx.phase = new_phase; 257 | } 258 | if(_ctx.reset_state){ 259 | if((fabsf(_ctx.reset_phase) > 10.f) || bdisable){ 260 | float reset_speed; 261 | if(bdisable){ 262 | reset_speed = 0.01f; 263 | } 264 | else 265 | { 266 | reset_speed = 0.5f; 267 | } 268 | _ctx.reset_phase = (_ctx.reset_phase + (- (_ctx.reset_phase * reset_speed))); 269 | } 270 | else 271 | { 272 | uint8_t _cond_17; 273 | _cond_17 = (_ctx.reset_phase > 10.f); 274 | if(bool_not(_cond_17)){ 275 | _ctx.reset_phase = 0.0f; 276 | } 277 | _ctx.reset_state = false; 278 | _ctx.direction = true; 279 | } 280 | out = _ctx.reset_phase; 281 | } 282 | out = (_ctx.phase + out); 283 | return (0.0009765625f * out); 284 | } 285 | 286 | void Swept__ctx_type_0_init(Swept__ctx_type_0 &_output_){ 287 | Swept__ctx_type_0 _ctx; 288 | _ctx.out = 0.0f; 289 | Util__ctx_type_0_init(_ctx._inst151); 290 | _output_ = _ctx; 291 | return ; 292 | } 293 | 294 | float Swept_process(Swept__ctx_type_0 &_ctx, float gate, float start, float end, float rate){ 295 | float a_rate; 296 | a_rate = (1.f / (0.01f + (100.f * rate))); 297 | uint8_t bgate; 298 | bgate = (gate > 0.5f); 299 | _ctx.out = (_ctx.out + (0.004f * rate * ((- _ctx.out) + (1024.f * end)))); 300 | if(Util_edge(_ctx._inst151,bgate)){ 301 | _ctx.out = (1024.f * start); 302 | } 303 | return (0.0009765625f * _ctx.out); 304 | } 305 | 306 | void Ahr__ctx_type_0_init(Ahr__ctx_type_0 &_output_){ 307 | Ahr__ctx_type_0 _ctx; 308 | _ctx.target = 0.0f; 309 | _ctx.state = 0; 310 | _ctx.rate = 0.0f; 311 | _ctx.out = 0.0f; 312 | _ctx.hold_phase = 0.0f; 313 | _ctx.do_ret_1 = 0.0f; 314 | _ctx.do_ret_0 = 0.0f; 315 | Util__ctx_type_0_init(_ctx._inst351); 316 | Util__ctx_type_0_init(_ctx._inst151); 317 | _output_ = _ctx; 318 | return ; 319 | } 320 | 321 | void Ahr_do(Ahr__ctx_type_0 &_ctx, float gate, float a, float h, float r){ 322 | int release; 323 | release = 0; 324 | int attack; 325 | attack = 1; 326 | int hold; 327 | hold = 2; 328 | int reset; 329 | reset = 3; 330 | uint8_t bgate; 331 | bgate = (gate > 0.0f); 332 | if(Util_edge(_ctx._inst151,bgate)){ 333 | _ctx.state = reset; 334 | } 335 | float resetting; 336 | if(_ctx.state == reset){ 337 | resetting = 1.f; 338 | } 339 | else 340 | { 341 | resetting = 0.0f; 342 | } 343 | if(Util_edge(_ctx._inst351,(_ctx.out > 1024.f))){ 344 | _ctx.hold_phase = 0.0f; 345 | _ctx.state = hold; 346 | } 347 | if((_ctx.out < 10.f) && (_ctx.state == reset)){ 348 | _ctx.state = attack; 349 | } 350 | if((_ctx.hold_phase > 100.f) && (_ctx.state == hold)){ 351 | _ctx.state = release; 352 | } 353 | if(_ctx.state == reset){ 354 | _ctx.rate = 0.990099009901f; 355 | _ctx.target = 0.0f; 356 | } 357 | if(_ctx.state == attack){ 358 | _ctx.rate = (1.f / (0.01f + (100.f * a))); 359 | _ctx.target = 1228.8f; 360 | } 361 | if(_ctx.state == hold){ 362 | float hrate; 363 | hrate = (1.f / (0.01f + (100.f * h))); 364 | _ctx.hold_phase = (_ctx.hold_phase + hrate); 365 | } 366 | if(_ctx.state == release){ 367 | _ctx.rate = (1.f / (0.01f + (100.f * r))); 368 | _ctx.target = 0.0f; 369 | } 370 | _ctx.out = (_ctx.out + (0.005f * _ctx.rate * (_ctx.target + (- _ctx.out)))); 371 | _ctx.do_ret_0 = float_clip((0.0009765625f * _ctx.out),0.0f,1.f); 372 | _ctx.do_ret_1 = resetting; 373 | return ; 374 | } 375 | 376 | void Ahr__ctx_type_1_init(Ahr__ctx_type_1 &_output_){ 377 | Ahr__ctx_type_1 _ctx; 378 | _ctx.process_ret_1 = 0.0f; 379 | _ctx.process_ret_0 = 0.0f; 380 | _ctx.knob3 = 0.0f; 381 | _ctx.knob2 = 0.0f; 382 | _ctx.knob1 = 0.0f; 383 | Ahr__ctx_type_0_init(_ctx._inst147); 384 | _output_ = _ctx; 385 | return ; 386 | } 387 | 388 | void Ahr_controlChange(Ahr__ctx_type_1 &_ctx, int control, int value, int channel){ 389 | if(control == 1){ 390 | _ctx.knob1 = (0.00787401574803f * int_to_float(value)); 391 | } 392 | if(control == 2){ 393 | _ctx.knob2 = (0.00787401574803f * int_to_float(value)); 394 | } 395 | if(control == 3){ 396 | _ctx.knob3 = (0.00787401574803f * int_to_float(value)); 397 | } 398 | } 399 | 400 | void Kick__ctx_type_0_init(Kick__ctx_type_0 &_output_){ 401 | Kick__ctx_type_0 _ctx; 402 | Noise__ctx_type_1_init(_ctx._inst5ab); 403 | Ahr__ctx_type_0_init(_ctx._inst447); 404 | Triangle__ctx_type_0_init(_ctx._inst3ca); 405 | Swept__ctx_type_0_init(_ctx._inst2eb); 406 | Ahr__ctx_type_0_init(_ctx._inst147); 407 | _output_ = _ctx; 408 | return ; 409 | } 410 | 411 | float Kick_do(Kick__ctx_type_0 &_ctx, float gate, float odecay, float pitch, float swept, float noise){ 412 | float osc_env; 413 | float env_reset; 414 | Ahr_do(_ctx._inst147,gate,0.005f,(0.1f + odecay),(0.01f + odecay)); 415 | osc_env = Ahr_do_ret_0(_ctx._inst147); 416 | env_reset = Ahr_do_ret_1(_ctx._inst147); 417 | float cv; 418 | cv = Swept_process(_ctx._inst2eb,(1.f + (- env_reset)),(pitch + (0.4f * swept)),pitch,0.1f); 419 | float osc; 420 | osc = Triangle_process(_ctx._inst3ca,cv,0.0f,env_reset); 421 | float osc_sat; 422 | osc_sat = Saturate_process((1.5f * osc)); 423 | float noise_env; 424 | Ahr_do(_ctx._inst447,gate,0.001f,0.01f,(0.001f + (0.01f * noise))); 425 | noise_env = Ahr_do_ret_0(_ctx._inst447); 426 | Ahr_do_ret_1(_ctx._inst447); 427 | float noise_osc; 428 | noise_osc = (0.333333333333f * noise * Noise_process(_ctx._inst5ab,1.f)); 429 | return ((noise_env * noise_osc) + (osc_env * osc_sat)); 430 | } 431 | 432 | void Kick__ctx_type_1_init(Kick__ctx_type_1 &_output_){ 433 | Kick__ctx_type_1 _ctx; 434 | _ctx.swept = 0.0f; 435 | _ctx.pitch = 0.0f; 436 | _ctx.odecay = 0.0f; 437 | _ctx.noise = 0.0f; 438 | Kick__ctx_type_0_init(_ctx._inst120); 439 | _output_ = _ctx; 440 | return ; 441 | } 442 | 443 | void Kick_controlChange(Kick__ctx_type_1 &_ctx, int control, int value, int channel){ 444 | if(control == 30){ 445 | _ctx.odecay = (0.00787401574803f * int_to_float(value)); 446 | } 447 | if(control == 31){ 448 | _ctx.pitch = Util_map(int_to_float(value),0.0f,127.f,0.0f,0.1f); 449 | } 450 | if(control == 32){ 451 | _ctx.swept = (0.00787401574803f * int_to_float(value)); 452 | } 453 | if(control == 33){ 454 | _ctx.noise = (0.00787401574803f * int_to_float(value)); 455 | } 456 | } 457 | 458 | void Phase__ctx_type_0_init(Phase__ctx_type_0 &_output_){ 459 | Phase__ctx_type_0 _ctx; 460 | _ctx.rate = 0.0f; 461 | _ctx.phase = 0.0f; 462 | Util__ctx_type_0_init(_ctx._inst351); 463 | Util__ctx_type_1_init(_ctx._inst13b); 464 | Phase_default(_ctx); 465 | _output_ = _ctx; 466 | return ; 467 | } 468 | 469 | float Phase_process(Phase__ctx_type_0 &_ctx, float cv, float reset){ 470 | if(Util_change(_ctx._inst13b,cv)){ 471 | _ctx.rate = Util_cvToRate_1024(cv); 472 | } 473 | if(Util_edge(_ctx._inst351,(reset > 0.5f))){ 474 | _ctx.phase = 0.0f; 475 | } 476 | else 477 | { 478 | _ctx.phase = (_ctx.phase + _ctx.rate); 479 | } 480 | if(_ctx.phase > 1024.f){ 481 | _ctx.phase = (-1024.f + _ctx.phase); 482 | } 483 | return (0.0009765625f * _ctx.phase); 484 | } 485 | 486 | void Sine__ctx_type_0_init(Sine__ctx_type_0 &_output_){ 487 | Sine__ctx_type_0 _ctx; 488 | _ctx.trig = false; 489 | Phase__ctx_type_0_init(_ctx.p); 490 | Util__ctx_type_0_init(_ctx._inst151); 491 | _output_ = _ctx; 492 | return ; 493 | } 494 | 495 | float Sine_process(Sine__ctx_type_0 &_ctx, float cv, float reset){ 496 | if(Util_edge(_ctx._inst151,(reset > 0.5f))){ 497 | _ctx.trig = true; 498 | } 499 | float phase; 500 | phase = Phase_process(_ctx.p,cv,0.0f); 501 | if((phase < 1e-18f) && _ctx.trig){ 502 | _ctx.trig = false; 503 | Phase_process(_ctx.p,cv,0.0f); 504 | } 505 | return Tables_nsine(phase); 506 | } 507 | 508 | 509 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/out.h: -------------------------------------------------------------------------------- 1 | 2 | /* Code automatically generated by Vult https://github.com/modlfo/vult */ 3 | #ifndef OUT_H 4 | #define OUT_H 5 | #include 6 | // #include 7 | #include "vultin.h" 8 | #include "out.tables.h" 9 | 10 | typedef struct _tuple___real_real__ { 11 | float field_0; 12 | float field_1; 13 | } _tuple___real_real__; 14 | 15 | typedef struct Noise__ctx_type_0 { 16 | float w1; 17 | } Noise__ctx_type_0; 18 | 19 | typedef Noise__ctx_type_0 Noise_pink_type; 20 | 21 | static_inline void Noise__ctx_type_0_init(Noise__ctx_type_0 &_output_){ 22 | Noise__ctx_type_0 _ctx; 23 | _ctx.w1 = 0.0f; 24 | _output_ = _ctx; 25 | return ; 26 | } 27 | 28 | static_inline void Noise_pink_init(Noise__ctx_type_0 &_output_){ 29 | Noise__ctx_type_0_init(_output_); 30 | return ; 31 | } 32 | 33 | float Noise_pink(Noise__ctx_type_0 &_ctx, float x); 34 | 35 | typedef struct Noise__ctx_type_1 { 36 | int x2; 37 | int x1; 38 | Noise__ctx_type_0 _inst1cc; 39 | } Noise__ctx_type_1; 40 | 41 | typedef Noise__ctx_type_1 Noise_process_type; 42 | 43 | void Noise__ctx_type_1_init(Noise__ctx_type_1 &_output_); 44 | 45 | static_inline void Noise_process_init(Noise__ctx_type_1 &_output_){ 46 | Noise__ctx_type_1_init(_output_); 47 | return ; 48 | } 49 | 50 | float Noise_process(Noise__ctx_type_1 &_ctx, float color); 51 | 52 | typedef Noise__ctx_type_1 Noise_noteOn_type; 53 | 54 | static_inline void Noise_noteOn_init(Noise__ctx_type_1 &_output_){ 55 | Noise__ctx_type_1_init(_output_); 56 | return ; 57 | } 58 | 59 | static_inline void Noise_noteOn(Noise__ctx_type_1 &_ctx, int note, int velocity, int channel){ 60 | } 61 | 62 | typedef Noise__ctx_type_1 Noise_noteOff_type; 63 | 64 | static_inline void Noise_noteOff_init(Noise__ctx_type_1 &_output_){ 65 | Noise__ctx_type_1_init(_output_); 66 | return ; 67 | } 68 | 69 | static_inline void Noise_noteOff(Noise__ctx_type_1 &_ctx, int note, int channel){ 70 | } 71 | 72 | typedef Noise__ctx_type_1 Noise_controlChange_type; 73 | 74 | static_inline void Noise_controlChange_init(Noise__ctx_type_1 &_output_){ 75 | Noise__ctx_type_1_init(_output_); 76 | return ; 77 | } 78 | 79 | static_inline void Noise_controlChange(Noise__ctx_type_1 &_ctx, int control, int value, int channel){ 80 | } 81 | 82 | typedef Noise__ctx_type_1 Noise_default_type; 83 | 84 | static_inline void Noise_default_init(Noise__ctx_type_1 &_output_){ 85 | Noise__ctx_type_1_init(_output_); 86 | return ; 87 | } 88 | 89 | static_inline void Noise_default(Noise__ctx_type_1 &_ctx){ 90 | } 91 | 92 | typedef struct Util__ctx_type_0 { 93 | uint8_t pre; 94 | } Util__ctx_type_0; 95 | 96 | typedef Util__ctx_type_0 Util_edge_type; 97 | 98 | static_inline void Util__ctx_type_0_init(Util__ctx_type_0 &_output_){ 99 | Util__ctx_type_0 _ctx; 100 | _ctx.pre = false; 101 | _output_ = _ctx; 102 | return ; 103 | } 104 | 105 | static_inline void Util_edge_init(Util__ctx_type_0 &_output_){ 106 | Util__ctx_type_0_init(_output_); 107 | return ; 108 | } 109 | 110 | static_inline uint8_t Util_edge(Util__ctx_type_0 &_ctx, uint8_t x){ 111 | uint8_t ret; 112 | ret = (x && bool_not(_ctx.pre)); 113 | _ctx.pre = x; 114 | return ret; 115 | } 116 | 117 | typedef struct Util__ctx_type_1 { 118 | float pre_x; 119 | } Util__ctx_type_1; 120 | 121 | typedef Util__ctx_type_1 Util_change_type; 122 | 123 | static_inline void Util__ctx_type_1_init(Util__ctx_type_1 &_output_){ 124 | Util__ctx_type_1 _ctx; 125 | _ctx.pre_x = 0.0f; 126 | _output_ = _ctx; 127 | return ; 128 | } 129 | 130 | static_inline void Util_change_init(Util__ctx_type_1 &_output_){ 131 | Util__ctx_type_1_init(_output_); 132 | return ; 133 | } 134 | 135 | static_inline uint8_t Util_change(Util__ctx_type_1 &_ctx, float x){ 136 | uint8_t v; 137 | v = (_ctx.pre_x != x); 138 | _ctx.pre_x = x; 139 | return v; 140 | } 141 | 142 | static_inline float Util_map(float x, float x0, float x1, float y0, float y1){ 143 | return (y0 + (((x + (- x0)) * (y1 + (- y0))) / (x1 + (- x0)))); 144 | }; 145 | 146 | typedef struct Util__ctx_type_3 { 147 | float y1; 148 | float x1; 149 | } Util__ctx_type_3; 150 | 151 | typedef Util__ctx_type_3 Util_dcblock_type; 152 | 153 | void Util__ctx_type_3_init(Util__ctx_type_3 &_output_); 154 | 155 | static_inline void Util_dcblock_init(Util__ctx_type_3 &_output_){ 156 | Util__ctx_type_3_init(_output_); 157 | return ; 158 | } 159 | 160 | float Util_dcblock(Util__ctx_type_3 &_ctx, float x0); 161 | 162 | typedef struct Util__ctx_type_4 { 163 | float x; 164 | } Util__ctx_type_4; 165 | 166 | typedef Util__ctx_type_4 Util_smooth_type; 167 | 168 | static_inline void Util__ctx_type_4_init(Util__ctx_type_4 &_output_){ 169 | Util__ctx_type_4 _ctx; 170 | _ctx.x = 0.0f; 171 | _output_ = _ctx; 172 | return ; 173 | } 174 | 175 | static_inline void Util_smooth_init(Util__ctx_type_4 &_output_){ 176 | Util__ctx_type_4_init(_output_); 177 | return ; 178 | } 179 | 180 | static_inline float Util_smooth(Util__ctx_type_4 &_ctx, float input){ 181 | _ctx.x = (_ctx.x + (0.005f * (input + (- _ctx.x)))); 182 | return _ctx.x; 183 | } 184 | 185 | typedef struct Util__ctx_type_5 { 186 | float x0; 187 | } Util__ctx_type_5; 188 | 189 | typedef Util__ctx_type_5 Util_average2_type; 190 | 191 | static_inline void Util__ctx_type_5_init(Util__ctx_type_5 &_output_){ 192 | Util__ctx_type_5 _ctx; 193 | _ctx.x0 = 0.0f; 194 | _output_ = _ctx; 195 | return ; 196 | } 197 | 198 | static_inline void Util_average2_init(Util__ctx_type_5 &_output_){ 199 | Util__ctx_type_5_init(_output_); 200 | return ; 201 | } 202 | 203 | static_inline float Util_average2(Util__ctx_type_5 &_ctx, float x1){ 204 | float result; 205 | result = (0.5f * (_ctx.x0 + x1)); 206 | _ctx.x0 = x1; 207 | return result; 208 | } 209 | 210 | static_inline float Util_cubic_clipper(float x){ 211 | if(x <= -0.666666666667f){ 212 | return -0.666666666667f; 213 | } 214 | else 215 | { 216 | if(x >= 0.666666666667f){ 217 | return 0.666666666667f; 218 | } 219 | else 220 | { 221 | return (x + (-0.333333333333f * x * x * x)); 222 | } 223 | } 224 | }; 225 | 226 | static_inline float Util_pitchToRate_1024_raw_c0(int index){ 227 | return Util_pitchToRate_1024_c0[index]; 228 | }; 229 | 230 | static_inline float Util_pitchToRate_1024_raw_c1(int index){ 231 | return Util_pitchToRate_1024_c1[index]; 232 | }; 233 | 234 | static_inline float Util_pitchToRate_1024_raw_c2(int index){ 235 | return Util_pitchToRate_1024_c2[index]; 236 | }; 237 | 238 | static_inline float Util_pitchToRate_1024(float pitch){ 239 | int index; 240 | index = int_clip(float_to_int((0.244094488189f * pitch)),0,31); 241 | return (float_wrap_array(Util_pitchToRate_1024_c0)[index] + (pitch * (float_wrap_array(Util_pitchToRate_1024_c1)[index] + (pitch * float_wrap_array(Util_pitchToRate_1024_c2)[index])))); 242 | } 243 | 244 | static_inline float Util_pitchToRate_raw_c0(int index){ 245 | return Util_pitchToRate_c0[index]; 246 | }; 247 | 248 | static_inline float Util_pitchToRate_raw_c1(int index){ 249 | return Util_pitchToRate_c1[index]; 250 | }; 251 | 252 | static_inline float Util_pitchToRate_raw_c2(int index){ 253 | return Util_pitchToRate_c2[index]; 254 | }; 255 | 256 | static_inline float Util_pitchToRate(float pitch){ 257 | int index; 258 | index = int_clip(float_to_int((0.244094488189f * pitch)),0,31); 259 | return (float_wrap_array(Util_pitchToRate_c0)[index] + (pitch * (float_wrap_array(Util_pitchToRate_c1)[index] + (pitch * float_wrap_array(Util_pitchToRate_c2)[index])))); 260 | } 261 | 262 | static_inline float Util_cvToPitch(float cv){ 263 | return (24.f + (120.f * cv)); 264 | }; 265 | 266 | static_inline float Util_cvToRate_1024_raw_c0(int index){ 267 | return Util_cvToRate_1024_c0[index]; 268 | }; 269 | 270 | static_inline float Util_cvToRate_1024_raw_c1(int index){ 271 | return Util_cvToRate_1024_c1[index]; 272 | }; 273 | 274 | static_inline float Util_cvToRate_1024_raw_c2(int index){ 275 | return Util_cvToRate_1024_c2[index]; 276 | }; 277 | 278 | static_inline float Util_cvToRate_1024(float cv){ 279 | int index; 280 | index = int_clip(float_to_int((34.4444444444f * cv)),0,31); 281 | return (float_wrap_array(Util_cvToRate_1024_c0)[index] + (cv * (float_wrap_array(Util_cvToRate_1024_c1)[index] + (cv * float_wrap_array(Util_cvToRate_1024_c2)[index])))); 282 | } 283 | 284 | static_inline float Util_cvToRate_raw_c0(int index){ 285 | return Util_cvToRate_c0[index]; 286 | }; 287 | 288 | static_inline float Util_cvToRate_raw_c1(int index){ 289 | return Util_cvToRate_c1[index]; 290 | }; 291 | 292 | static_inline float Util_cvToRate_raw_c2(int index){ 293 | return Util_cvToRate_c2[index]; 294 | }; 295 | 296 | static_inline float Util_cvToRate(float cv){ 297 | int index; 298 | index = int_clip(float_to_int((141.111111111f * cv)),0,127); 299 | return (float_wrap_array(Util_cvToRate_c0)[index] + (cv * (float_wrap_array(Util_cvToRate_c1)[index] + (cv * float_wrap_array(Util_cvToRate_c2)[index])))); 300 | } 301 | 302 | static_inline float Util_pitchToCv(float pitch){ 303 | return (0.00833333333333f * (-24.f + pitch)); 304 | }; 305 | 306 | static_inline float Util_cvToperiod_raw_c0(int index){ 307 | return Util_cvToperiod_c0[index]; 308 | }; 309 | 310 | static_inline float Util_cvToperiod_raw_c1(int index){ 311 | return Util_cvToperiod_c1[index]; 312 | }; 313 | 314 | static_inline float Util_cvToperiod_raw_c2(int index){ 315 | return Util_cvToperiod_c2[index]; 316 | }; 317 | 318 | static_inline float Util_cvToperiod(float cv){ 319 | int index; 320 | index = int_clip(float_to_int((31.f * cv)),0,31); 321 | return (float_wrap_array(Util_cvToperiod_c0)[index] + (cv * (float_wrap_array(Util_cvToperiod_c1)[index] + (cv * float_wrap_array(Util_cvToperiod_c2)[index])))); 322 | } 323 | 324 | static_inline float Util_cvTokHz_raw_c0(int index){ 325 | return Util_cvTokHz_c0[index]; 326 | }; 327 | 328 | static_inline float Util_cvTokHz_raw_c1(int index){ 329 | return Util_cvTokHz_c1[index]; 330 | }; 331 | 332 | static_inline float Util_cvTokHz_raw_c2(int index){ 333 | return Util_cvTokHz_c2[index]; 334 | }; 335 | 336 | static_inline float Util_cvTokHz(float cv){ 337 | int index; 338 | index = int_clip(float_to_int((31.f * cv)),0,31); 339 | return (float_wrap_array(Util_cvTokHz_c0)[index] + (cv * (float_wrap_array(Util_cvTokHz_c1)[index] + (cv * float_wrap_array(Util_cvTokHz_c2)[index])))); 340 | } 341 | 342 | static_inline float Ladder_tune_raw_c0(int index){ 343 | return Ladder_tune_c0[index]; 344 | }; 345 | 346 | static_inline float Ladder_tune_raw_c1(int index){ 347 | return Ladder_tune_c1[index]; 348 | }; 349 | 350 | static_inline float Ladder_tune_raw_c2(int index){ 351 | return Ladder_tune_c2[index]; 352 | }; 353 | 354 | static_inline float Ladder_tune(float cut){ 355 | int index; 356 | index = int_clip(float_to_int((127.f * cut)),0,127); 357 | return (float_wrap_array(Ladder_tune_c0)[index] + (cut * (float_wrap_array(Ladder_tune_c1)[index] + (cut * float_wrap_array(Ladder_tune_c2)[index])))); 358 | } 359 | 360 | typedef struct Ladder__ctx_type_4 { 361 | float p3; 362 | float p2; 363 | float p1; 364 | float p0; 365 | } Ladder__ctx_type_4; 366 | 367 | typedef Ladder__ctx_type_4 Ladder_heun_type; 368 | 369 | void Ladder__ctx_type_4_init(Ladder__ctx_type_4 &_output_); 370 | 371 | static_inline void Ladder_heun_init(Ladder__ctx_type_4 &_output_){ 372 | Ladder__ctx_type_4_init(_output_); 373 | return ; 374 | } 375 | 376 | float Ladder_heun(Ladder__ctx_type_4 &_ctx, float input, float fh, float res); 377 | 378 | typedef struct Ladder__ctx_type_5 { 379 | float p3; 380 | float p2; 381 | float p1; 382 | float p0; 383 | } Ladder__ctx_type_5; 384 | 385 | typedef Ladder__ctx_type_5 Ladder_euler_type; 386 | 387 | void Ladder__ctx_type_5_init(Ladder__ctx_type_5 &_output_); 388 | 389 | static_inline void Ladder_euler_init(Ladder__ctx_type_5 &_output_){ 390 | Ladder__ctx_type_5_init(_output_); 391 | return ; 392 | } 393 | 394 | float Ladder_euler(Ladder__ctx_type_5 &_ctx, float input, float fh, float res); 395 | 396 | typedef struct Ladder__ctx_type_6 { 397 | float fh; 398 | Ladder__ctx_type_5 e; 399 | Util__ctx_type_1 _inst13b; 400 | } Ladder__ctx_type_6; 401 | 402 | typedef Ladder__ctx_type_6 Ladder_process_euler_type; 403 | 404 | void Ladder__ctx_type_6_init(Ladder__ctx_type_6 &_output_); 405 | 406 | static_inline void Ladder_process_euler_init(Ladder__ctx_type_6 &_output_){ 407 | Ladder__ctx_type_6_init(_output_); 408 | return ; 409 | } 410 | 411 | float Ladder_process_euler(Ladder__ctx_type_6 &_ctx, float input, float cut, float res); 412 | 413 | typedef struct Ladder__ctx_type_7 { 414 | Ladder__ctx_type_4 h; 415 | float fh; 416 | Util__ctx_type_1 _inst13b; 417 | } Ladder__ctx_type_7; 418 | 419 | typedef Ladder__ctx_type_7 Ladder_process_heun_type; 420 | 421 | void Ladder__ctx_type_7_init(Ladder__ctx_type_7 &_output_); 422 | 423 | static_inline void Ladder_process_heun_init(Ladder__ctx_type_7 &_output_){ 424 | Ladder__ctx_type_7_init(_output_); 425 | return ; 426 | } 427 | 428 | float Ladder_process_heun(Ladder__ctx_type_7 &_ctx, float input, float cut, float res); 429 | 430 | typedef struct Ladder__ctx_type_8 { 431 | Ladder__ctx_type_7 _inst112; 432 | } Ladder__ctx_type_8; 433 | 434 | typedef Ladder__ctx_type_8 Ladder_process_type; 435 | 436 | static_inline void Ladder__ctx_type_8_init(Ladder__ctx_type_8 &_output_){ 437 | Ladder__ctx_type_8 _ctx; 438 | Ladder__ctx_type_7_init(_ctx._inst112); 439 | _output_ = _ctx; 440 | return ; 441 | } 442 | 443 | static_inline void Ladder_process_init(Ladder__ctx_type_8 &_output_){ 444 | Ladder__ctx_type_8_init(_output_); 445 | return ; 446 | } 447 | 448 | static_inline float Ladder_process(Ladder__ctx_type_8 &_ctx, float input, float cut, float res){ 449 | return Ladder_process_heun(_ctx._inst112,input,cut,res); 450 | }; 451 | 452 | typedef struct Triangle__ctx_type_0 { 453 | uint8_t reset_state; 454 | float reset_phase; 455 | float rate; 456 | float phase; 457 | uint8_t direction; 458 | Util__ctx_type_0 _inst451; 459 | Util__ctx_type_0 _inst351; 460 | Util__ctx_type_1 _inst13b; 461 | } Triangle__ctx_type_0; 462 | 463 | typedef Triangle__ctx_type_0 Triangle_process_type; 464 | 465 | void Triangle__ctx_type_0_init(Triangle__ctx_type_0 &_output_); 466 | 467 | static_inline void Triangle_process_init(Triangle__ctx_type_0 &_output_){ 468 | Triangle__ctx_type_0_init(_output_); 469 | return ; 470 | } 471 | 472 | float Triangle_process(Triangle__ctx_type_0 &_ctx, float cv, float reset, float disable); 473 | 474 | typedef Triangle__ctx_type_0 Triangle_noteOn_type; 475 | 476 | static_inline void Triangle_noteOn_init(Triangle__ctx_type_0 &_output_){ 477 | Triangle__ctx_type_0_init(_output_); 478 | return ; 479 | } 480 | 481 | static_inline void Triangle_noteOn(Triangle__ctx_type_0 &_ctx, int note, int velocity, int channel){ 482 | } 483 | 484 | typedef Triangle__ctx_type_0 Triangle_noteOff_type; 485 | 486 | static_inline void Triangle_noteOff_init(Triangle__ctx_type_0 &_output_){ 487 | Triangle__ctx_type_0_init(_output_); 488 | return ; 489 | } 490 | 491 | static_inline void Triangle_noteOff(Triangle__ctx_type_0 &_ctx, int note, int channel){ 492 | } 493 | 494 | typedef Triangle__ctx_type_0 Triangle_controlChange_type; 495 | 496 | static_inline void Triangle_controlChange_init(Triangle__ctx_type_0 &_output_){ 497 | Triangle__ctx_type_0_init(_output_); 498 | return ; 499 | } 500 | 501 | static_inline void Triangle_controlChange(Triangle__ctx_type_0 &_ctx, int control, int value, int channel){ 502 | } 503 | 504 | typedef Triangle__ctx_type_0 Triangle_default_type; 505 | 506 | static_inline void Triangle_default_init(Triangle__ctx_type_0 &_output_){ 507 | Triangle__ctx_type_0_init(_output_); 508 | return ; 509 | } 510 | 511 | static_inline void Triangle_default(Triangle__ctx_type_0 &_ctx){ 512 | _ctx.rate = 0.759366720147f; 513 | }; 514 | 515 | typedef struct Swept__ctx_type_0 { 516 | float out; 517 | Util__ctx_type_0 _inst151; 518 | } Swept__ctx_type_0; 519 | 520 | typedef Swept__ctx_type_0 Swept_process_type; 521 | 522 | void Swept__ctx_type_0_init(Swept__ctx_type_0 &_output_); 523 | 524 | static_inline void Swept_process_init(Swept__ctx_type_0 &_output_){ 525 | Swept__ctx_type_0_init(_output_); 526 | return ; 527 | } 528 | 529 | float Swept_process(Swept__ctx_type_0 &_ctx, float gate, float start, float end, float rate); 530 | 531 | typedef Swept__ctx_type_0 Swept_noteOn_type; 532 | 533 | static_inline void Swept_noteOn_init(Swept__ctx_type_0 &_output_){ 534 | Swept__ctx_type_0_init(_output_); 535 | return ; 536 | } 537 | 538 | static_inline void Swept_noteOn(Swept__ctx_type_0 &_ctx, int note, int velocity, int channel){ 539 | } 540 | 541 | typedef Swept__ctx_type_0 Swept_noteOff_type; 542 | 543 | static_inline void Swept_noteOff_init(Swept__ctx_type_0 &_output_){ 544 | Swept__ctx_type_0_init(_output_); 545 | return ; 546 | } 547 | 548 | static_inline void Swept_noteOff(Swept__ctx_type_0 &_ctx, int note, int channel){ 549 | } 550 | 551 | typedef Swept__ctx_type_0 Swept_controlChange_type; 552 | 553 | static_inline void Swept_controlChange_init(Swept__ctx_type_0 &_output_){ 554 | Swept__ctx_type_0_init(_output_); 555 | return ; 556 | } 557 | 558 | static_inline void Swept_controlChange(Swept__ctx_type_0 &_ctx, int control, int value, int channel){ 559 | } 560 | 561 | typedef Swept__ctx_type_0 Swept_default_type; 562 | 563 | static_inline void Swept_default_init(Swept__ctx_type_0 &_output_){ 564 | Swept__ctx_type_0_init(_output_); 565 | return ; 566 | } 567 | 568 | static_inline void Swept_default(Swept__ctx_type_0 &_ctx){ 569 | } 570 | 571 | static_inline float Saturate_tanh_table_raw_c0(int index){ 572 | return Saturate_tanh_table_c0[index]; 573 | }; 574 | 575 | static_inline float Saturate_tanh_table_raw_c1(int index){ 576 | return Saturate_tanh_table_c1[index]; 577 | }; 578 | 579 | static_inline float Saturate_tanh_table_raw_c2(int index){ 580 | return Saturate_tanh_table_c2[index]; 581 | }; 582 | 583 | static_inline float Saturate_tanh_table(float x){ 584 | int index; 585 | index = int_clip(float_to_int((5.f * (24.f + x))),0,240); 586 | return (float_wrap_array(Saturate_tanh_table_c0)[index] + (x * (float_wrap_array(Saturate_tanh_table_c1)[index] + (x * float_wrap_array(Saturate_tanh_table_c2)[index])))); 587 | } 588 | 589 | static_inline float Saturate_process(float x){ 590 | return Saturate_tanh_table(x); 591 | }; 592 | 593 | static_inline void Saturate_noteOn(int note, int velocity, int channel){ 594 | } 595 | 596 | static_inline void Saturate_noteOff(int note, int channel){ 597 | } 598 | 599 | static_inline void Saturate_controlChange(int control, int value, int channel){ 600 | } 601 | 602 | static_inline void Saturate_default(){ 603 | } 604 | 605 | typedef struct Ahr__ctx_type_0 { 606 | float target; 607 | int state; 608 | float rate; 609 | float out; 610 | float hold_phase; 611 | float do_ret_1; 612 | float do_ret_0; 613 | Util__ctx_type_0 _inst351; 614 | Util__ctx_type_0 _inst151; 615 | } Ahr__ctx_type_0; 616 | 617 | typedef Ahr__ctx_type_0 Ahr_do_type; 618 | 619 | void Ahr__ctx_type_0_init(Ahr__ctx_type_0 &_output_); 620 | 621 | static_inline void Ahr_do_init(Ahr__ctx_type_0 &_output_){ 622 | Ahr__ctx_type_0_init(_output_); 623 | return ; 624 | } 625 | 626 | void Ahr_do(Ahr__ctx_type_0 &_ctx, float gate, float a, float h, float r); 627 | 628 | typedef Ahr__ctx_type_0 Ahr_do_ret_0_type; 629 | 630 | static_inline void Ahr_do_ret_0_init(Ahr__ctx_type_0 &_output_){ 631 | Ahr__ctx_type_0_init(_output_); 632 | return ; 633 | } 634 | 635 | static_inline float Ahr_do_ret_0(Ahr__ctx_type_0 &_ctx){ 636 | return _ctx.do_ret_0; 637 | }; 638 | 639 | typedef Ahr__ctx_type_0 Ahr_do_ret_1_type; 640 | 641 | static_inline void Ahr_do_ret_1_init(Ahr__ctx_type_0 &_output_){ 642 | Ahr__ctx_type_0_init(_output_); 643 | return ; 644 | } 645 | 646 | static_inline float Ahr_do_ret_1(Ahr__ctx_type_0 &_ctx){ 647 | return _ctx.do_ret_1; 648 | }; 649 | 650 | typedef struct Ahr__ctx_type_1 { 651 | float process_ret_1; 652 | float process_ret_0; 653 | float knob3; 654 | float knob2; 655 | float knob1; 656 | Ahr__ctx_type_0 _inst147; 657 | } Ahr__ctx_type_1; 658 | 659 | typedef Ahr__ctx_type_1 Ahr_process_type; 660 | 661 | void Ahr__ctx_type_1_init(Ahr__ctx_type_1 &_output_); 662 | 663 | static_inline void Ahr_process_init(Ahr__ctx_type_1 &_output_){ 664 | Ahr__ctx_type_1_init(_output_); 665 | return ; 666 | } 667 | 668 | static_inline void Ahr_process(Ahr__ctx_type_1 &_ctx, float gate){ 669 | Ahr_do(_ctx._inst147,gate,_ctx.knob1,_ctx.knob2,_ctx.knob3); 670 | _ctx.process_ret_0 = Ahr_do_ret_0(_ctx._inst147); 671 | _ctx.process_ret_1 = Ahr_do_ret_1(_ctx._inst147); 672 | return ; 673 | } 674 | 675 | typedef Ahr__ctx_type_1 Ahr_process_ret_0_type; 676 | 677 | static_inline void Ahr_process_ret_0_init(Ahr__ctx_type_1 &_output_){ 678 | Ahr__ctx_type_1_init(_output_); 679 | return ; 680 | } 681 | 682 | static_inline float Ahr_process_ret_0(Ahr__ctx_type_1 &_ctx){ 683 | return _ctx.process_ret_0; 684 | }; 685 | 686 | typedef Ahr__ctx_type_1 Ahr_process_ret_1_type; 687 | 688 | static_inline void Ahr_process_ret_1_init(Ahr__ctx_type_1 &_output_){ 689 | Ahr__ctx_type_1_init(_output_); 690 | return ; 691 | } 692 | 693 | static_inline float Ahr_process_ret_1(Ahr__ctx_type_1 &_ctx){ 694 | return _ctx.process_ret_1; 695 | }; 696 | 697 | typedef Ahr__ctx_type_1 Ahr_noteOn_type; 698 | 699 | static_inline void Ahr_noteOn_init(Ahr__ctx_type_1 &_output_){ 700 | Ahr__ctx_type_1_init(_output_); 701 | return ; 702 | } 703 | 704 | static_inline void Ahr_noteOn(Ahr__ctx_type_1 &_ctx, int note, int velocity, int channel){ 705 | } 706 | 707 | typedef Ahr__ctx_type_1 Ahr_noteOff_type; 708 | 709 | static_inline void Ahr_noteOff_init(Ahr__ctx_type_1 &_output_){ 710 | Ahr__ctx_type_1_init(_output_); 711 | return ; 712 | } 713 | 714 | static_inline void Ahr_noteOff(Ahr__ctx_type_1 &_ctx, int note, int channel){ 715 | } 716 | 717 | typedef Ahr__ctx_type_1 Ahr_controlChange_type; 718 | 719 | static_inline void Ahr_controlChange_init(Ahr__ctx_type_1 &_output_){ 720 | Ahr__ctx_type_1_init(_output_); 721 | return ; 722 | } 723 | 724 | void Ahr_controlChange(Ahr__ctx_type_1 &_ctx, int control, int value, int channel); 725 | 726 | typedef Ahr__ctx_type_1 Ahr_default_type; 727 | 728 | static_inline void Ahr_default_init(Ahr__ctx_type_1 &_output_){ 729 | Ahr__ctx_type_1_init(_output_); 730 | return ; 731 | } 732 | 733 | static_inline void Ahr_default(Ahr__ctx_type_1 &_ctx){ 734 | _ctx.knob1 = 0.0f; 735 | _ctx.knob2 = 0.5f; 736 | _ctx.knob3 = 0.5f; 737 | } 738 | 739 | typedef struct Kick__ctx_type_0 { 740 | Noise__ctx_type_1 _inst5ab; 741 | Ahr__ctx_type_0 _inst447; 742 | Triangle__ctx_type_0 _inst3ca; 743 | Swept__ctx_type_0 _inst2eb; 744 | Ahr__ctx_type_0 _inst147; 745 | } Kick__ctx_type_0; 746 | 747 | typedef Kick__ctx_type_0 Kick_do_type; 748 | 749 | void Kick__ctx_type_0_init(Kick__ctx_type_0 &_output_); 750 | 751 | static_inline void Kick_do_init(Kick__ctx_type_0 &_output_){ 752 | Kick__ctx_type_0_init(_output_); 753 | return ; 754 | } 755 | 756 | float Kick_do(Kick__ctx_type_0 &_ctx, float gate, float odecay, float pitch, float swept, float noise); 757 | 758 | typedef struct Kick__ctx_type_1 { 759 | float swept; 760 | float pitch; 761 | float odecay; 762 | float noise; 763 | Kick__ctx_type_0 _inst120; 764 | } Kick__ctx_type_1; 765 | 766 | typedef Kick__ctx_type_1 Kick_process_type; 767 | 768 | void Kick__ctx_type_1_init(Kick__ctx_type_1 &_output_); 769 | 770 | static_inline void Kick_process_init(Kick__ctx_type_1 &_output_){ 771 | Kick__ctx_type_1_init(_output_); 772 | return ; 773 | } 774 | 775 | static_inline float Kick_process(Kick__ctx_type_1 &_ctx, float gate){ 776 | return Kick_do(_ctx._inst120,gate,_ctx.odecay,_ctx.pitch,_ctx.swept,_ctx.noise); 777 | }; 778 | 779 | typedef Kick__ctx_type_1 Kick_noteOn_type; 780 | 781 | static_inline void Kick_noteOn_init(Kick__ctx_type_1 &_output_){ 782 | Kick__ctx_type_1_init(_output_); 783 | return ; 784 | } 785 | 786 | static_inline void Kick_noteOn(Kick__ctx_type_1 &_ctx, int note, int velocity, int channel){ 787 | } 788 | 789 | typedef Kick__ctx_type_1 Kick_noteOff_type; 790 | 791 | static_inline void Kick_noteOff_init(Kick__ctx_type_1 &_output_){ 792 | Kick__ctx_type_1_init(_output_); 793 | return ; 794 | } 795 | 796 | static_inline void Kick_noteOff(Kick__ctx_type_1 &_ctx, int note, int channel){ 797 | } 798 | 799 | typedef Kick__ctx_type_1 Kick_controlChange_type; 800 | 801 | static_inline void Kick_controlChange_init(Kick__ctx_type_1 &_output_){ 802 | Kick__ctx_type_1_init(_output_); 803 | return ; 804 | } 805 | 806 | void Kick_controlChange(Kick__ctx_type_1 &_ctx, int control, int value, int channel); 807 | 808 | typedef Kick__ctx_type_1 Kick_default_type; 809 | 810 | static_inline void Kick_default_init(Kick__ctx_type_1 &_output_){ 811 | Kick__ctx_type_1_init(_output_); 812 | return ; 813 | } 814 | 815 | static_inline void Kick_default(Kick__ctx_type_1 &_ctx){ 816 | } 817 | 818 | typedef struct Phase__ctx_type_0 { 819 | float rate; 820 | float phase; 821 | Util__ctx_type_0 _inst351; 822 | Util__ctx_type_1 _inst13b; 823 | } Phase__ctx_type_0; 824 | 825 | typedef Phase__ctx_type_0 Phase_process_type; 826 | 827 | void Phase__ctx_type_0_init(Phase__ctx_type_0 &_output_); 828 | 829 | static_inline void Phase_process_init(Phase__ctx_type_0 &_output_){ 830 | Phase__ctx_type_0_init(_output_); 831 | return ; 832 | } 833 | 834 | float Phase_process(Phase__ctx_type_0 &_ctx, float cv, float reset); 835 | 836 | typedef Phase__ctx_type_0 Phase_noteOn_type; 837 | 838 | static_inline void Phase_noteOn_init(Phase__ctx_type_0 &_output_){ 839 | Phase__ctx_type_0_init(_output_); 840 | return ; 841 | } 842 | 843 | static_inline void Phase_noteOn(Phase__ctx_type_0 &_ctx, int note, int velocity, int channel){ 844 | } 845 | 846 | typedef Phase__ctx_type_0 Phase_noteOff_type; 847 | 848 | static_inline void Phase_noteOff_init(Phase__ctx_type_0 &_output_){ 849 | Phase__ctx_type_0_init(_output_); 850 | return ; 851 | } 852 | 853 | static_inline void Phase_noteOff(Phase__ctx_type_0 &_ctx, int note, int channel){ 854 | } 855 | 856 | typedef Phase__ctx_type_0 Phase_controlChange_type; 857 | 858 | static_inline void Phase_controlChange_init(Phase__ctx_type_0 &_output_){ 859 | Phase__ctx_type_0_init(_output_); 860 | return ; 861 | } 862 | 863 | static_inline void Phase_controlChange(Phase__ctx_type_0 &_ctx, int control, int value, int channel){ 864 | } 865 | 866 | typedef Phase__ctx_type_0 Phase_default_type; 867 | 868 | static_inline void Phase_default_init(Phase__ctx_type_0 &_output_){ 869 | Phase__ctx_type_0_init(_output_); 870 | return ; 871 | } 872 | 873 | static_inline void Phase_default(Phase__ctx_type_0 &_ctx){ 874 | _ctx.rate = 0.759366720147f; 875 | }; 876 | 877 | static_inline float Tables_nsine_raw_c0(int index){ 878 | return Tables_nsine_c0[index]; 879 | }; 880 | 881 | static_inline float Tables_nsine_raw_c1(int index){ 882 | return Tables_nsine_c1[index]; 883 | }; 884 | 885 | static_inline float Tables_nsine_raw_c2(int index){ 886 | return Tables_nsine_c2[index]; 887 | }; 888 | 889 | static_inline float Tables_nsine(float x){ 890 | int index; 891 | index = int_clip(float_to_int((127.f * x)),0,127); 892 | return (float_wrap_array(Tables_nsine_c0)[index] + (x * (float_wrap_array(Tables_nsine_c1)[index] + (x * float_wrap_array(Tables_nsine_c2)[index])))); 893 | } 894 | 895 | typedef struct Sine__ctx_type_0 { 896 | uint8_t trig; 897 | Phase__ctx_type_0 p; 898 | Util__ctx_type_0 _inst151; 899 | } Sine__ctx_type_0; 900 | 901 | typedef Sine__ctx_type_0 Sine_process_type; 902 | 903 | void Sine__ctx_type_0_init(Sine__ctx_type_0 &_output_); 904 | 905 | static_inline void Sine_process_init(Sine__ctx_type_0 &_output_){ 906 | Sine__ctx_type_0_init(_output_); 907 | return ; 908 | } 909 | 910 | float Sine_process(Sine__ctx_type_0 &_ctx, float cv, float reset); 911 | 912 | 913 | 914 | #endif // OUT_H 915 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/saturate.vult: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2017 Leonardo Laguna Ruiz 5 | ----- 6 | Tanh satuation 7 | */ 8 | 9 | fun tanh_table(x:real) @[table(min = -24.0, max = 24.0, size = 241)]{ 10 | return tanh(x); 11 | } 12 | 13 | fun process(x) { 14 | return tanh_table(x); 15 | } 16 | and noteOn(note:int,velocity:int,channel:int){ } 17 | and noteOff(note:int,channel:int){ } 18 | and controlChange(control:int,value:int,channel:int){ } 19 | and default() { } 20 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/sine.vult: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2017 Leonardo Laguna Ruiz 5 | ----- 6 | Sin oscillator reset control 7 | */ 8 | 9 | fun process(cv, reset) { 10 | mem trig; 11 | if(Util.edge(reset > 0.5)) { 12 | trig = true; 13 | } 14 | val phase = p:Phase.process(cv, 0.0); 15 | // the frequency changes only during the zero crossings 16 | if(phase < eps() && trig) { 17 | trig = false; 18 | _ = p:Phase.process(cv, 0.0); 19 | } 20 | return Tables.nsine(phase); 21 | } 22 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/swept.vult: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2017 Leonardo Laguna Ruiz 5 | ----- 6 | Produces a signal that goes from 'start' to 'end' at a given rate 7 | when 'gate' is triggered. 8 | */ 9 | 10 | fun process(gate, start, end, rate) { 11 | mem out; 12 | val a_rate = 1.0 / (100.0 * rate + 0.01); 13 | val bgate = gate > 0.5; 14 | out = out + ((end * 1024.0) - out) * rate * 0.004; 15 | if(Util.edge(bgate)) 16 | out = start * 1024.0; 17 | return out/1024.0; 18 | } 19 | 20 | and noteOn(note:int,velocity:int,channel:int){ } 21 | and noteOff(note:int,channel:int){ } 22 | and controlChange(control:int,value:int,channel:int){ } 23 | and default(){ } 24 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/triangle.vult: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2017 Leonardo Laguna Ruiz 5 | */ 6 | 7 | // Vult is a simple and powerful language to program high-performance 8 | // algorithms that may run in small microprocessors or microcontrollers. 9 | // Vult is specially useful when programming Digital Signal Processing (DSP) 10 | // algorithms like audio effects or synthesizers. 11 | 12 | // Triangle oscillator with reset 13 | fun process(cv:real, reset:real, disable:real) : real { 14 | mem rate; 15 | mem reset_state; 16 | mem phase, reset_phase; 17 | mem direction; 18 | val out = 0.0; 19 | // Calculate the rate only when the cv changes 20 | if(Util.change(cv)) { 21 | rate = 4.0 * Util.cvToRate_1024(cv); 22 | } 23 | // Determine the next value 24 | val new_phase = phase + if direction then rate else -rate; 25 | 26 | val bdisable = disable > 0.5; 27 | 28 | // if reset or disable were triggered, then enter reset state 29 | if(Util.edge(reset > 0.0) || Util.edge(bdisable)) { 30 | // this is gonna be the initial value from which the oscillator starts resetting 31 | reset_phase = phase; 32 | // enter the reset state 33 | reset_state = true; 34 | new_phase = 0.0; 35 | } 36 | 37 | // wrap the phase in both directions 38 | if(new_phase > 1024.0) { 39 | new_phase = 1024.0 - (new_phase - 1024.0); 40 | direction = false; 41 | } 42 | else if(new_phase < -1024.0) { 43 | direction = true; 44 | new_phase = -1024.0 + (new_phase + 1024.0); 45 | } 46 | // update the phase, if disabled just make it zero 47 | phase = if bdisable then 0.0 else new_phase; 48 | 49 | if(reset_state) { 50 | // exponentially reduce the value until, if it's reset and not disabled 51 | // when the value is very small goes out of reset state 52 | if(abs(reset_phase) > 10.0 || bdisable) { 53 | // `disable` produces a softer transition 54 | val reset_speed = if bdisable then 0.01 else 0.5; 55 | reset_phase = reset_phase - reset_phase * reset_speed; 56 | } 57 | else { 58 | reset_phase = if reset_phase > 10.0 then reset_phase else 0.0; 59 | reset_state = false; 60 | direction = true; 61 | } 62 | out = reset_phase; 63 | } 64 | // the output is the sum of the ideal saw wave and the reset transition 65 | out = out + phase; 66 | return out / 1024.0; 67 | } 68 | and noteOn(note:int,velocity:int,channel:int){ } 69 | and noteOff(note:int,channel:int){ } 70 | and controlChange(control:int,value:int,channel:int){ } 71 | and default() @[init] { 72 | rate = Util.cvToRate_1024(0.0); 73 | } 74 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/vultin.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Leonardo Laguna Ruiz 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | 25 | 26 | NOTE: The code for the fixed-point operations is based on the project: 27 | https://code.google.com/p/libfixmath/ 28 | 29 | */ 30 | #include "vultin.h" 31 | // #include "stdio.h" 32 | 33 | fix16_t fix_exp(fix16_t inValue) { 34 | if (inValue == 0) 35 | return 0x00010000; 36 | if (inValue == 0x00010000) 37 | return 178145; 38 | if (inValue >= 681391) 39 | return 0x7FFFFFFF; 40 | if (inValue <= -772243) 41 | return 0; 42 | // The power-series converges much faster on positive values 43 | // and exp(-x) = 1/exp(x). 44 | int neg = (inValue < 0); 45 | if (neg) 46 | inValue = -inValue; 47 | fix16_t result = inValue + 0x00010000; 48 | fix16_t term = inValue; 49 | uint_fast8_t i; 50 | for (i = 2; i < 30; i++) { 51 | term = fix_mul(term, fix_div(inValue, int_to_fix(i))); 52 | result += term; 53 | if ((term < 500) && ((i > 15) || (term < 20))) 54 | break; 55 | } 56 | if (neg) 57 | result = fix_div(0x00010000, result); 58 | return result; 59 | } 60 | 61 | fix16_t fix_sin(fix16_t x0) { 62 | fix16_t x1 = (x0 % 0x6487e /* 6.283185 */); 63 | uint8_t sign = (x1 > 0x3243f /* 3.141593 */); 64 | fix16_t x2 = (x1 % 0x3243f /* 3.141593 */); 65 | fix16_t x3; 66 | if (x2 > 0x1921f /* 1.570796 */) 67 | x3 = fix_add(0x3243f /* 3.141593 */, (-x2)); 68 | else 69 | x3 = x2; 70 | fix16_t xp2 = fix_mul(x3, x3); 71 | fix16_t acc = 72 | fix_mul(x3, fix_add(0x10000 /* 1.000000 */, 73 | fix_mul(fix_add((0xffffd556 /* -0.166667 */), 74 | fix_mul(0x222 /* 0.008333 */, xp2)), 75 | xp2))); 76 | return (sign ? (-acc) : acc); 77 | } 78 | 79 | fix16_t fix_cos(fix16_t inAngle) { return fix_sin(inAngle + (fix_pi() >> 1)); } 80 | 81 | fix16_t fix_tan(fix16_t inAngle) { 82 | return fix_div(fix_sin(inAngle), fix_cos(inAngle)); 83 | } 84 | 85 | fix16_t fix_sinh(fix16_t inAngle) { 86 | return fix_mul(fix_exp(inAngle) - fix_exp(-inAngle), 0x8000); 87 | } 88 | 89 | fix16_t fix_cosh(fix16_t inAngle) { 90 | return fix_mul(fix_exp(inAngle) + fix_exp(-inAngle), 0x8000); 91 | } 92 | 93 | fix16_t fix_tanh(fix16_t inAngle) { 94 | fix16_t e_x = fix_exp(inAngle); 95 | fix16_t m_e_x = fix_exp(-inAngle); 96 | return fix_div(e_x - m_e_x, e_x + m_e_x); 97 | } 98 | 99 | fix16_t fix_sqrt(fix16_t inValue) { 100 | uint8_t neg = (inValue < 0); 101 | uint32_t num = (neg ? -inValue : inValue); 102 | uint32_t result = 0; 103 | uint32_t bit; 104 | uint8_t n; 105 | 106 | // Many numbers will be less than 15, so 107 | // this gives a good balance between time spent 108 | // in if vs. time spent in the while loop 109 | // when searching for the starting value. 110 | if (num & 0xFFF00000) 111 | bit = (uint32_t)1 << 30; 112 | else 113 | bit = (uint32_t)1 << 18; 114 | 115 | while (bit > num) 116 | bit >>= 2; 117 | 118 | // The main part is executed twice, in order to avoid 119 | // using 64 bit values in computations. 120 | for (n = 0; n < 2; n++) { 121 | // First we get the top 24 bits of the answer. 122 | while (bit) { 123 | if (num >= result + bit) { 124 | num -= result + bit; 125 | result = (result >> 1) + bit; 126 | } else { 127 | result = (result >> 1); 128 | } 129 | bit >>= 2; 130 | } 131 | 132 | if (n == 0) { 133 | // Then process it again to get the lowest 8 bits. 134 | if (num > 65535) { 135 | // The remainder 'num' is too large to be shifted left 136 | // by 16, so we have to add 1 to result manually and 137 | // adjust 'num' accordingly. 138 | // num = a - (result + 0.5)^2 139 | // = num + result^2 - (result + 0.5)^2 140 | // = num - result - 0.5 141 | num -= result; 142 | num = (num << 16) - 0x8000; 143 | result = (result << 16) + 0x8000; 144 | } else { 145 | num <<= 16; 146 | result <<= 16; 147 | } 148 | 149 | bit = 1 << 14; 150 | } 151 | } 152 | return (neg ? -(int32_t)result : (int32_t)result); 153 | } 154 | 155 | /* Array initialization */ 156 | void float_init_array(size_t size, float value, float data[]) { 157 | size_t i; 158 | for (i = 0; i < size; i++) 159 | data[i] = value; 160 | } 161 | 162 | void int_init_array(size_t size, int value, int data[]) { 163 | size_t i; 164 | for (i = 0; i < size; i++) 165 | data[i] = value; 166 | } 167 | 168 | void bool_init_array(size_t size, uint8_t value, uint8_t data[]) { 169 | size_t i; 170 | for (i = 0; i < size; i++) 171 | data[i] = value; 172 | } 173 | 174 | void fix_init_array(size_t size, fix16_t value, fix16_t data[]) { 175 | size_t i; 176 | for (i = 0; i < size; i++) 177 | data[i] = value; 178 | } 179 | 180 | void float_copy_array(size_t size, float *dest, float *src) { 181 | size_t i; 182 | for (i = 0; i < size; i++) 183 | dest[i] = src[i]; 184 | } 185 | 186 | void int_copy_array(size_t size, int *dest, int *src) { 187 | size_t i; 188 | for (i = 0; i < size; i++) 189 | dest[i] = src[i]; 190 | } 191 | 192 | void bool_copy_array(size_t size, uint8_t *dest, uint8_t *src) { 193 | size_t i; 194 | for (i = 0; i < size; i++) 195 | dest[i] = src[i]; 196 | } 197 | 198 | void fix_copy_array(size_t size, fix16_t *dest, fix16_t *src) { 199 | size_t i; 200 | for (i = 0; i < size; i++) 201 | dest[i] = src[i]; 202 | } 203 | 204 | // float float_random() { return (float)rand() / RAND_MAX; } 205 | 206 | // fix16_t fix_random() { 207 | // float temp = ((float)rand() / RAND_MAX) * 0x00010000; 208 | // return (fix16_t)temp; 209 | // } 210 | 211 | // int irandom() { return (int)rand(); } 212 | 213 | // void float_print(float value) { printf("%f\n", value); } 214 | // void fix_print(fix16_t value) { printf("%f\n", fix_to_float(value)); } 215 | // void int_print(int value) { printf("%i\n", value); } 216 | // void string_print(char *value) { printf("%s\n", value); } 217 | // void bool_print(uint8_t value) { printf("%s\n", value ? "true" : "false"); } 218 | -------------------------------------------------------------------------------- /Guest/Sources/VultDSP/vultin.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Leonardo Laguna Ruiz 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | 25 | 26 | NOTE: The code for the fixed-point operations is based on the project: 27 | https://code.google.com/p/libfixmath/ 28 | 29 | */ 30 | 31 | #ifndef VULTIN_H 32 | #define VULTIN_H 33 | 34 | // #include 35 | #include 36 | #include 37 | // #include 38 | 39 | #ifdef _MSC_VER 40 | #define static_inline static __inline 41 | #else 42 | #define static_inline static inline 43 | #endif 44 | 45 | typedef int32_t fix16_t; 46 | 47 | extern float float_samplerate(); 48 | extern fix16_t fix_samplerate(); 49 | 50 | // Type conversion 51 | static_inline float fix_to_float(fix16_t a) { return (float)a / 0x00010000; } 52 | static_inline fix16_t float_to_fix(float a) { 53 | float temp = a * 0x00010000; 54 | return (fix16_t)temp; 55 | } 56 | 57 | static_inline fix16_t short_to_fix(int16_t x) { 58 | return 0x8000 & x ? 0xFFFF0000 | x : x; 59 | } 60 | 61 | static_inline int16_t fix_to_short(fix16_t x) { 62 | return (x >= 0x00010000 ? 0x00010000 - 1 : x) / 2; 63 | } 64 | 65 | static_inline float short_to_float(int16_t x) { return (float)x / 0x00010000; } 66 | 67 | static_inline float int_to_float(int a) { return (float)a; } 68 | 69 | static_inline int float_to_int(float a) { return (int)a; } 70 | 71 | static_inline fix16_t int_to_fix(int a) { return a * 0x00010000; } 72 | 73 | static_inline int fix_to_int(fix16_t a) { return (a >> 16); } 74 | 75 | static_inline int int_clip(int v, int minv, int maxv) { 76 | return v > maxv ? maxv : (v < minv ? minv : v); 77 | } 78 | 79 | // Basic operations for fixed point numbers 80 | static_inline fix16_t fix_add(fix16_t x, fix16_t y) { return x + y; } 81 | 82 | static_inline fix16_t fix_sub(fix16_t x, fix16_t y) { return x - y; } 83 | 84 | static_inline fix16_t fix_mul(fix16_t x, fix16_t y) { 85 | int64_t res = (int64_t)x * y; 86 | return (fix16_t)(res >> 16); 87 | } 88 | 89 | static_inline fix16_t fix_div(fix16_t a, fix16_t b) { 90 | if (b == 0) 91 | return 0; 92 | fix16_t result = (((int64_t)a) << 16) / ((int64_t)b); 93 | return result; 94 | } 95 | 96 | static_inline fix16_t fix_mac(fix16_t x, fix16_t y, fix16_t z) { 97 | return x + fix_mul(y, z); 98 | } 99 | 100 | static_inline fix16_t fix_msu(fix16_t x, fix16_t y, fix16_t z) { 101 | return -x + fix_mul(y, z); 102 | } 103 | 104 | static_inline fix16_t fix_minus(fix16_t x) { return -x; } 105 | 106 | static_inline fix16_t fix_abs(fix16_t x) { return x < 0 ? (-x) : x; } 107 | 108 | static_inline fix16_t fix_min(fix16_t a, fix16_t b) { return a < b ? a : b; } 109 | 110 | static_inline fix16_t fix_max(fix16_t a, fix16_t b) { return a > b ? a : b; } 111 | 112 | static_inline fix16_t fix_clip(fix16_t v, fix16_t minv, fix16_t maxv) { 113 | return v > maxv ? maxv : (v < minv ? minv : v); 114 | } 115 | 116 | static_inline fix16_t fix_floor(fix16_t x) { return (x & 0xFFFF0000); } 117 | 118 | static_inline fix16_t fix_not(fix16_t x) { return ~x; } 119 | 120 | static_inline float float_eps() { return 1e-18f; } 121 | 122 | static_inline fix16_t fix_eps() { return 1; } 123 | 124 | static_inline float float_pi() { return 3.1415926535897932384f; } 125 | 126 | static_inline fix16_t fix_pi() { return 205887; } 127 | 128 | static_inline float float_mac(float x, float y, float z) { 129 | return x + (y * z); 130 | } 131 | 132 | static_inline float float_msu(float x, float y, float z) { 133 | return -x + (y * z); 134 | } 135 | 136 | fix16_t fix_exp(fix16_t inValue); 137 | 138 | fix16_t fix_sin(fix16_t inAngle); 139 | 140 | fix16_t fix_cos(fix16_t inAngle); 141 | 142 | fix16_t fix_tan(fix16_t inAngle); 143 | 144 | fix16_t fix_sinh(fix16_t inAngle); 145 | 146 | fix16_t fix_cosh(fix16_t inAngle); 147 | 148 | fix16_t fix_tanh(fix16_t inAngle); 149 | 150 | fix16_t fix_sqrt(fix16_t inValue); 151 | 152 | /* Floating point operations */ 153 | 154 | static_inline float float_clip(float value, float low, float high) { 155 | return value < low ? low : (value > high ? high : value); 156 | } 157 | 158 | /* Array get and set */ 159 | static_inline void float_set(float a[], int i, float value) { a[i] = value; } 160 | static_inline float float_get(float a[], int i) { return a[i]; } 161 | static_inline void fix_set(fix16_t a[], int i, fix16_t value) { a[i] = value; } 162 | static_inline fix16_t fix_get(fix16_t a[], int i) { return a[i]; } 163 | static_inline void int_set(int a[], int i, int value) { a[i] = value; } 164 | static_inline int int_get(int a[], int i) { return a[i]; } 165 | static_inline void bool_set(uint8_t a[], int i, uint8_t value) { a[i] = value; } 166 | static_inline uint8_t bool_get(uint8_t a[], int i) { return a[i]; } 167 | 168 | /* Array initialization */ 169 | void float_init_array(size_t size, float value, float data[]); 170 | void int_init_array(size_t size, int value, int data[]); 171 | void bool_init_array(size_t size, uint8_t value, uint8_t data[]); 172 | void fix_init_array(size_t size, fix16_t value, fix16_t data[]); 173 | 174 | /* Array copy */ 175 | void float_copy_array(size_t size, float *dest, float *src); 176 | void int_copy_array(size_t size, int *dest, int *src); 177 | void bool_copy_array(size_t size, uint8_t *dest, uint8_t *src); 178 | void fix_copy_array(size_t size, fix16_t *dest, fix16_t *src); 179 | 180 | static_inline uint8_t bool_not(uint8_t x) { return !x; } 181 | 182 | /* Tables */ 183 | static_inline fix16_t *fix_wrap_array(const fix16_t x[]) { 184 | return (fix16_t *)x; 185 | }; 186 | static_inline float *float_wrap_array(const float x[]) { return (float *)x; }; 187 | 188 | /* Random numbers */ 189 | float float_random(); 190 | fix16_t fix_random(); 191 | int irandom(); 192 | 193 | /* Print values */ 194 | void float_print(float value); 195 | void fix_print(fix16_t value); 196 | void int_print(int value); 197 | void string_print(char *value); 198 | void bool_print(uint8_t value); 199 | 200 | template 201 | T abs_template(T t) 202 | { 203 | return t>0 ? t : -t; 204 | } 205 | 206 | static inline float fabsf(float f) { 207 | return abs_template(f); 208 | } 209 | 210 | #endif // VULTIN_H 211 | -------------------------------------------------------------------------------- /Guest/Sources/dlmalloc/include/__macro_PAGESIZE.h: -------------------------------------------------------------------------------- 1 | #ifndef __wasilibc___macro_PAGESIZE_h 2 | #define __wasilibc___macro_PAGESIZE_h 3 | 4 | /* 5 | * The page size in WebAssembly is fixed at 64 KiB. If this ever changes, 6 | * it's expected that applications will need to opt in, so we can change 7 | * this. 8 | * 9 | * If this ever needs to be a value outside the range of an `int`, the 10 | * `getpagesize` function which returns this value will need special 11 | * consideration. POSIX has deprecated `getpagesize` in favor of 12 | * `sysconf(_SC_PAGESIZE)` which does not have this problem. 13 | */ 14 | #define PAGESIZE (0x10000) 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /Guest/Sources/dlmalloc/include/endian.h: -------------------------------------------------------------------------------- 1 | #ifndef _ENDIAN_H 2 | #define _ENDIAN_H 3 | 4 | #include 5 | 6 | #define __NEED_uint16_t 7 | #define __NEED_uint32_t 8 | #define __NEED_uint64_t 9 | 10 | #include 11 | 12 | #define __PDP_ENDIAN 3412 13 | 14 | #define BIG_ENDIAN __BIG_ENDIAN 15 | #define LITTLE_ENDIAN __LITTLE_ENDIAN 16 | #define PDP_ENDIAN __PDP_ENDIAN 17 | #define BYTE_ORDER __BYTE_ORDER 18 | 19 | static __inline uint16_t __bswap16(uint16_t __x) 20 | { 21 | return __x<<8 | __x>>8; 22 | } 23 | 24 | static __inline uint32_t __bswap32(uint32_t __x) 25 | { 26 | return __x>>24 | __x>>8&0xff00 | __x<<8&0xff0000 | __x<<24; 27 | } 28 | 29 | static __inline uint64_t __bswap64(uint64_t __x) 30 | { 31 | return (__bswap32(__x)+0ULL)<<32 | __bswap32(__x>>32); 32 | } 33 | 34 | #if __BYTE_ORDER == __LITTLE_ENDIAN 35 | #define htobe16(x) __bswap16(x) 36 | #define be16toh(x) __bswap16(x) 37 | #define htobe32(x) __bswap32(x) 38 | #define be32toh(x) __bswap32(x) 39 | #define htobe64(x) __bswap64(x) 40 | #define be64toh(x) __bswap64(x) 41 | #define htole16(x) (uint16_t)(x) 42 | #define le16toh(x) (uint16_t)(x) 43 | #define htole32(x) (uint32_t)(x) 44 | #define le32toh(x) (uint32_t)(x) 45 | #define htole64(x) (uint64_t)(x) 46 | #define le64toh(x) (uint64_t)(x) 47 | #else 48 | #define htobe16(x) (uint16_t)(x) 49 | #define be16toh(x) (uint16_t)(x) 50 | #define htobe32(x) (uint32_t)(x) 51 | #define be32toh(x) (uint32_t)(x) 52 | #define htobe64(x) (uint64_t)(x) 53 | #define be64toh(x) (uint64_t)(x) 54 | #define htole16(x) __bswap16(x) 55 | #define le16toh(x) __bswap16(x) 56 | #define htole32(x) __bswap32(x) 57 | #define le32toh(x) __bswap32(x) 58 | #define htole64(x) __bswap64(x) 59 | #define le64toh(x) __bswap64(x) 60 | #endif 61 | 62 | #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) 63 | #if __BYTE_ORDER == __LITTLE_ENDIAN 64 | #define betoh16(x) __bswap16(x) 65 | #define betoh32(x) __bswap32(x) 66 | #define betoh64(x) __bswap64(x) 67 | #define letoh16(x) (uint16_t)(x) 68 | #define letoh32(x) (uint32_t)(x) 69 | #define letoh64(x) (uint64_t)(x) 70 | #else 71 | #define betoh16(x) (uint16_t)(x) 72 | #define betoh32(x) (uint32_t)(x) 73 | #define betoh64(x) (uint64_t)(x) 74 | #define letoh16(x) __bswap16(x) 75 | #define letoh32(x) __bswap32(x) 76 | #define letoh64(x) __bswap64(x) 77 | #endif 78 | #endif 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /Guest/Sources/dlmalloc/include/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef __wasilibc___errno_values_h 2 | #define __wasilibc___errno_values_h 3 | 4 | extern int errno; 5 | 6 | #include 7 | 8 | #define E2BIG __WASI_ERRNO_2BIG 9 | #define EACCES __WASI_ERRNO_ACCES 10 | #define EADDRINUSE __WASI_ERRNO_ADDRINUSE 11 | #define EADDRNOTAVAIL __WASI_ERRNO_ADDRNOTAVAIL 12 | #define EAFNOSUPPORT __WASI_ERRNO_AFNOSUPPORT 13 | #define EAGAIN __WASI_ERRNO_AGAIN 14 | #define EALREADY __WASI_ERRNO_ALREADY 15 | #define EBADF __WASI_ERRNO_BADF 16 | #define EBADMSG __WASI_ERRNO_BADMSG 17 | #define EBUSY __WASI_ERRNO_BUSY 18 | #define ECANCELED __WASI_ERRNO_CANCELED 19 | #define ECHILD __WASI_ERRNO_CHILD 20 | #define ECONNABORTED __WASI_ERRNO_CONNABORTED 21 | #define ECONNREFUSED __WASI_ERRNO_CONNREFUSED 22 | #define ECONNRESET __WASI_ERRNO_CONNRESET 23 | #define EDEADLK __WASI_ERRNO_DEADLK 24 | #define EDESTADDRREQ __WASI_ERRNO_DESTADDRREQ 25 | #define EDOM __WASI_ERRNO_DOM 26 | #define EDQUOT __WASI_ERRNO_DQUOT 27 | #define EEXIST __WASI_ERRNO_EXIST 28 | #define EFAULT __WASI_ERRNO_FAULT 29 | #define EFBIG __WASI_ERRNO_FBIG 30 | #define EHOSTUNREACH __WASI_ERRNO_HOSTUNREACH 31 | #define EIDRM __WASI_ERRNO_IDRM 32 | #define EILSEQ __WASI_ERRNO_ILSEQ 33 | #define EINPROGRESS __WASI_ERRNO_INPROGRESS 34 | #define EINTR __WASI_ERRNO_INTR 35 | #define EINVAL __WASI_ERRNO_INVAL 36 | #define EIO __WASI_ERRNO_IO 37 | #define EISCONN __WASI_ERRNO_ISCONN 38 | #define EISDIR __WASI_ERRNO_ISDIR 39 | #define ELOOP __WASI_ERRNO_LOOP 40 | #define EMFILE __WASI_ERRNO_MFILE 41 | #define EMLINK __WASI_ERRNO_MLINK 42 | #define EMSGSIZE __WASI_ERRNO_MSGSIZE 43 | #define EMULTIHOP __WASI_ERRNO_MULTIHOP 44 | #define ENAMETOOLONG __WASI_ERRNO_NAMETOOLONG 45 | #define ENETDOWN __WASI_ERRNO_NETDOWN 46 | #define ENETRESET __WASI_ERRNO_NETRESET 47 | #define ENETUNREACH __WASI_ERRNO_NETUNREACH 48 | #define ENFILE __WASI_ERRNO_NFILE 49 | #define ENOBUFS __WASI_ERRNO_NOBUFS 50 | #define ENODEV __WASI_ERRNO_NODEV 51 | #define ENOENT __WASI_ERRNO_NOENT 52 | #define ENOEXEC __WASI_ERRNO_NOEXEC 53 | #define ENOLCK __WASI_ERRNO_NOLCK 54 | #define ENOLINK __WASI_ERRNO_NOLINK 55 | #define ENOMEM __WASI_ERRNO_NOMEM 56 | #define ENOMSG __WASI_ERRNO_NOMSG 57 | #define ENOPROTOOPT __WASI_ERRNO_NOPROTOOPT 58 | #define ENOSPC __WASI_ERRNO_NOSPC 59 | #define ENOSYS __WASI_ERRNO_NOSYS 60 | #define ENOTCONN __WASI_ERRNO_NOTCONN 61 | #define ENOTDIR __WASI_ERRNO_NOTDIR 62 | #define ENOTEMPTY __WASI_ERRNO_NOTEMPTY 63 | #define ENOTRECOVERABLE __WASI_ERRNO_NOTRECOVERABLE 64 | #define ENOTSOCK __WASI_ERRNO_NOTSOCK 65 | #define ENOTSUP __WASI_ERRNO_NOTSUP 66 | #define ENOTTY __WASI_ERRNO_NOTTY 67 | #define ENXIO __WASI_ERRNO_NXIO 68 | #define EOVERFLOW __WASI_ERRNO_OVERFLOW 69 | #define EOWNERDEAD __WASI_ERRNO_OWNERDEAD 70 | #define EPERM __WASI_ERRNO_PERM 71 | #define EPIPE __WASI_ERRNO_PIPE 72 | #define EPROTO __WASI_ERRNO_PROTO 73 | #define EPROTONOSUPPORT __WASI_ERRNO_PROTONOSUPPORT 74 | #define EPROTOTYPE __WASI_ERRNO_PROTOTYPE 75 | #define ERANGE __WASI_ERRNO_RANGE 76 | #define EROFS __WASI_ERRNO_ROFS 77 | #define ESPIPE __WASI_ERRNO_SPIPE 78 | #define ESRCH __WASI_ERRNO_SRCH 79 | #define ESTALE __WASI_ERRNO_STALE 80 | #define ETIMEDOUT __WASI_ERRNO_TIMEDOUT 81 | #define ETXTBSY __WASI_ERRNO_TXTBSY 82 | #define EXDEV __WASI_ERRNO_XDEV 83 | #define ENOTCAPABLE __WASI_ERRNO_NOTCAPABLE 84 | 85 | #define EOPNOTSUPP ENOTSUP 86 | #define EWOULDBLOCK EAGAIN 87 | 88 | #endif -------------------------------------------------------------------------------- /Guest/Sources/dlmalloc/include/features.h: -------------------------------------------------------------------------------- 1 | #ifndef _FEATURES_H 2 | #define _FEATURES_H 3 | 4 | #if __STDC_VERSION__ >= 199901L 5 | #define __restrict restrict 6 | #elif !defined(__GNUC__) 7 | #define __restrict 8 | #endif 9 | 10 | #if __STDC_VERSION__ >= 199901L || defined(__cplusplus) 11 | #define __inline inline 12 | #elif !defined(__GNUC__) 13 | #define __inline 14 | #endif 15 | 16 | #if __STDC_VERSION__ >= 201112L 17 | #elif defined(__GNUC__) 18 | #define _Noreturn __attribute__((__noreturn__)) 19 | #else 20 | #define _Noreturn 21 | #endif 22 | 23 | #define __REDIR(x,y) __typeof__(x) x __asm__(#y) 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /Guest/Sources/dlmalloc/include/malloc.h: -------------------------------------------------------------------------------- 1 | #ifndef _MALLOC_H 2 | #define _MALLOC_H 3 | 4 | #ifdef __wasilibc_unmodified_upstream /* Use alternate WASI libc headers */ 5 | #else 6 | #include <__functions_malloc.h> 7 | #endif 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include 13 | #include "string.h" 14 | 15 | #ifdef __wasilibc_unmodified_upstream /* Use alternate WASI libc headers */ 16 | void *malloc (size_t); 17 | void *calloc (size_t, size_t); 18 | void *realloc (void *, size_t); 19 | void free (void *); 20 | #endif 21 | #ifdef __wasilibc_unmodified_upstream /* WASI libc doesn't build the legacy functions */ 22 | void *valloc (size_t); 23 | void *memalign(size_t, size_t); 24 | #endif 25 | 26 | size_t malloc_usable_size(void *); 27 | 28 | void abort(void) __attribute__((noreturn)); 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | 34 | #endif -------------------------------------------------------------------------------- /Guest/Sources/dlmalloc/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRING_H 2 | #define _STRING_H 3 | 4 | #ifdef __wasilibc_unmodified_upstream /* Use alternate WASI libc headers */ 5 | #else 6 | #include <__header_string.h> 7 | #endif 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include 13 | #include 14 | 15 | #define __NEED_size_t 16 | #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ 17 | || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \ 18 | || defined(_BSD_SOURCE) 19 | #define __NEED_locale_t 20 | #endif 21 | 22 | #ifdef __wasilibc_unmodified_upstream /* Use alternate WASI libc headers */ 23 | void *memcpy (void *__restrict, const void *__restrict, size_t); 24 | void *memmove (void *, const void *, size_t); 25 | void *memset (void *, int, size_t); 26 | #endif 27 | int memcmp (const void *, const void *, size_t); 28 | #ifdef __wasilibc_unmodified_upstream /* Use alternate WASI libc headers */ 29 | void *memchr (const void *, int, size_t); 30 | #endif 31 | 32 | char *strcpy (char *__restrict, const char *__restrict); 33 | 34 | char *strcat (char *__restrict, const char *__restrict); 35 | 36 | #ifdef __wasilibc_unmodified_upstream /* Use alternate WASI libc headers */ 37 | int strcmp (const char *, const char *); 38 | #endif 39 | int strncmp (const char *, const char *, size_t); 40 | 41 | int strcoll (const char *, const char *); 42 | size_t strxfrm (char *__restrict, const char *__restrict, size_t); 43 | 44 | char *strchr (const char *, int); 45 | char *strrchr (const char *, int); 46 | 47 | size_t strcspn (const char *, const char *); 48 | size_t strspn (const char *, const char *); 49 | char *strpbrk (const char *, const char *); 50 | char *strstr (const char *, const char *); 51 | char *strtok (char *__restrict, const char *__restrict); 52 | 53 | #ifdef __wasilibc_unmodified_upstream /* Use alternate WASI libc headers */ 54 | size_t strlen (const char *); 55 | #endif 56 | 57 | char *strerror (int); 58 | 59 | #if defined(_BSD_SOURCE) || defined(_GNU_SOURCE) 60 | #include 61 | #endif 62 | 63 | #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ 64 | || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \ 65 | || defined(_BSD_SOURCE) 66 | char *strtok_r (char *__restrict, const char *__restrict, char **__restrict); 67 | int strerror_r (int, char *, size_t); 68 | char *stpcpy(char *__restrict, const char *__restrict); 69 | char *stpncpy(char *__restrict, const char *__restrict, size_t); 70 | size_t strnlen (const char *, size_t); 71 | #ifdef __wasilibc_unmodified_upstream /* Use alternate WASI libc headers */ 72 | char *strdup (const char *); 73 | #endif 74 | char *strndup (const char *, size_t); 75 | char *strsignal(int); 76 | char *strerror_l (int, locale_t); 77 | int strcoll_l (const char *, const char *, locale_t); 78 | size_t strxfrm_l (char *__restrict, const char *__restrict, size_t, locale_t); 79 | #endif 80 | 81 | #if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \ 82 | || defined(_BSD_SOURCE) 83 | void *memccpy (void *__restrict, const void *__restrict, int, size_t); 84 | #endif 85 | 86 | #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) 87 | char *strsep(char **, const char *); 88 | size_t strlcat (char *, const char *, size_t); 89 | size_t strlcpy (char *, const char *, size_t); 90 | void explicit_bzero (void *, size_t); 91 | #endif 92 | 93 | #ifdef _GNU_SOURCE 94 | #define strdupa(x) strcpy(alloca(strlen(x)+1),x) 95 | int strverscmp (const char *, const char *); 96 | char *strchrnul(const char *, int); 97 | char *strcasestr(const char *, const char *); 98 | void *memmem(const void *, size_t, const void *, size_t); 99 | void *memrchr(const void *, int, size_t); 100 | void *mempcpy(void *, const void *, size_t); 101 | #ifdef __wasilibc_unmodified_upstream /* avoid unprototyped decls; use */ 102 | #ifndef __cplusplus 103 | char *basename(); 104 | #endif 105 | #endif 106 | #endif 107 | 108 | #ifdef __cplusplus 109 | } 110 | #endif 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /Guest/Sources/dlmalloc/include/unistd.h: -------------------------------------------------------------------------------- 1 | /* Stub include file to support dlmalloc. */ 2 | 3 | #include 4 | #include <__macro_PAGESIZE.h> 5 | 6 | #define sysconf(name) PAGESIZE 7 | #define _SC_PAGESIZE 8 | 9 | /* Declare sbrk. */ 10 | void *sbrk(intptr_t increment) __attribute__((__warn_unused_result__)); 11 | -------------------------------------------------------------------------------- /Guest/Sources/dlmalloc/src/abort.c: -------------------------------------------------------------------------------- 1 | #include "malloc.h" 2 | 3 | void abort(void) { 4 | __builtin_unreachable(); 5 | } 6 | -------------------------------------------------------------------------------- /Guest/Sources/dlmalloc/src/dlmalloc.c: -------------------------------------------------------------------------------- 1 | // This file is a wrapper around malloc.c, which is the upstream source file. 2 | // It sets configuration flags and controls which symbols are exported. 3 | 4 | #include 5 | #include 6 | 7 | // Define configuration macros for dlmalloc. 8 | 9 | // WebAssembly doesn't have mmap-style memory allocation. 10 | #define HAVE_MMAP 0 11 | 12 | // WebAssembly doesn't support shrinking linear memory. 13 | #define MORECORE_CANNOT_TRIM 1 14 | 15 | // Disable checks to reduce code size. 16 | #define ABORT __builtin_unreachable() 17 | 18 | // If threads are enabled, enable support for threads. 19 | #ifdef _REENTRANT 20 | #define USE_LOCKS 1 21 | #endif 22 | 23 | // Make malloc deterministic. 24 | #define LACKS_TIME_H 1 25 | 26 | // Disable malloc statistics generation to reduce code size. 27 | #define NO_MALLINFO 1 28 | #define NO_MALLOC_STATS 1 29 | 30 | // Align malloc regions to 16, to avoid unaligned SIMD accesses. 31 | #define MALLOC_ALIGNMENT 16 32 | 33 | // Define USE_DL_PREFIX so that we leave dlmalloc's names prefixed with 'dl'. 34 | // We define them as "static", and we wrap them with public names below. This 35 | // serves two purposes: 36 | // 37 | // One is to make it easy to control which symbols are exported; dlmalloc 38 | // defines several non-standard functions and we wish to explicitly control 39 | // which functions are part of our public-facing interface. 40 | // 41 | // The other is to protect against compilers optimizing based on the assumption 42 | // that they know what functions with names like "malloc" do. Code in the 43 | // implementation will call functions like "dlmalloc" and assume it can use 44 | // the resulting pointers to access the metadata outside of the nominally 45 | // allocated objects. However, if the function were named "malloc", compilers 46 | // might see code like that and assume it has undefined behavior and can be 47 | // optimized away. By using "dlmalloc" in the implementation, we don't need 48 | // -fno-builtin to avoid this problem. 49 | #define USE_DL_PREFIX 1 50 | #define DLMALLOC_EXPORT static inline 51 | 52 | // This isn't declared with DLMALLOC_EXPORT so make it static explicitly. 53 | static size_t dlmalloc_usable_size(void*); 54 | 55 | // Include the upstream dlmalloc's malloc.c. 56 | #include "upstream_malloc.h" 57 | 58 | // Export the public names. 59 | 60 | void *malloc(size_t size) { 61 | return dlmalloc(size); 62 | } 63 | 64 | void free(void *ptr) { 65 | dlfree(ptr); 66 | } 67 | 68 | void *calloc(size_t nmemb, size_t size) { 69 | return dlcalloc(nmemb, size); 70 | } 71 | 72 | void *realloc(void *ptr, size_t size) { 73 | return dlrealloc(ptr, size); 74 | } 75 | 76 | int posix_memalign(void **memptr, size_t alignment, size_t size) { 77 | return dlposix_memalign(memptr, alignment, size); 78 | } 79 | 80 | void* aligned_alloc(size_t alignment, size_t bytes) { 81 | return dlmemalign(alignment, bytes); 82 | } 83 | 84 | size_t malloc_usable_size(void *ptr) { 85 | return dlmalloc_usable_size(ptr); 86 | } 87 | 88 | // Define these to satisfy musl references. 89 | void *__libc_malloc(size_t) __attribute__((alias("malloc"))); 90 | void __libc_free(void *) __attribute__((alias("free"))); 91 | void *__libc_calloc(size_t nmemb, size_t size) __attribute__((alias("calloc"))); 92 | -------------------------------------------------------------------------------- /Guest/Sources/dlmalloc/src/errno.c: -------------------------------------------------------------------------------- 1 | int errno = 0; -------------------------------------------------------------------------------- /Guest/Sources/dlmalloc/src/memcpy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void *memcpy(void *restrict dest, const void *restrict src, size_t n) 6 | { 7 | #if defined(__wasm_bulk_memory__) 8 | if (n > BULK_MEMORY_THRESHOLD) 9 | return __builtin_memcpy(dest, src, n); 10 | #endif 11 | unsigned char *d = dest; 12 | const unsigned char *s = src; 13 | 14 | #ifdef __GNUC__ 15 | 16 | #if __BYTE_ORDER == __LITTLE_ENDIAN 17 | #define LS >> 18 | #define RS << 19 | #else 20 | #define LS << 21 | #define RS >> 22 | #endif 23 | 24 | typedef uint32_t __attribute__((__may_alias__)) u32; 25 | uint32_t w, x; 26 | 27 | for (; (uintptr_t)s % 4 && n; n--) *d++ = *s++; 28 | 29 | if ((uintptr_t)d % 4 == 0) { 30 | for (; n>=16; s+=16, d+=16, n-=16) { 31 | *(u32 *)(d+0) = *(u32 *)(s+0); 32 | *(u32 *)(d+4) = *(u32 *)(s+4); 33 | *(u32 *)(d+8) = *(u32 *)(s+8); 34 | *(u32 *)(d+12) = *(u32 *)(s+12); 35 | } 36 | if (n&8) { 37 | *(u32 *)(d+0) = *(u32 *)(s+0); 38 | *(u32 *)(d+4) = *(u32 *)(s+4); 39 | d += 8; s += 8; 40 | } 41 | if (n&4) { 42 | *(u32 *)(d+0) = *(u32 *)(s+0); 43 | d += 4; s += 4; 44 | } 45 | if (n&2) { 46 | *d++ = *s++; *d++ = *s++; 47 | } 48 | if (n&1) { 49 | *d = *s; 50 | } 51 | return dest; 52 | } 53 | 54 | if (n >= 32) switch ((uintptr_t)d % 4) { 55 | case 1: 56 | w = *(u32 *)s; 57 | *d++ = *s++; 58 | *d++ = *s++; 59 | *d++ = *s++; 60 | n -= 3; 61 | for (; n>=17; s+=16, d+=16, n-=16) { 62 | x = *(u32 *)(s+1); 63 | *(u32 *)(d+0) = (w LS 24) | (x RS 8); 64 | w = *(u32 *)(s+5); 65 | *(u32 *)(d+4) = (x LS 24) | (w RS 8); 66 | x = *(u32 *)(s+9); 67 | *(u32 *)(d+8) = (w LS 24) | (x RS 8); 68 | w = *(u32 *)(s+13); 69 | *(u32 *)(d+12) = (x LS 24) | (w RS 8); 70 | } 71 | break; 72 | case 2: 73 | w = *(u32 *)s; 74 | *d++ = *s++; 75 | *d++ = *s++; 76 | n -= 2; 77 | for (; n>=18; s+=16, d+=16, n-=16) { 78 | x = *(u32 *)(s+2); 79 | *(u32 *)(d+0) = (w LS 16) | (x RS 16); 80 | w = *(u32 *)(s+6); 81 | *(u32 *)(d+4) = (x LS 16) | (w RS 16); 82 | x = *(u32 *)(s+10); 83 | *(u32 *)(d+8) = (w LS 16) | (x RS 16); 84 | w = *(u32 *)(s+14); 85 | *(u32 *)(d+12) = (x LS 16) | (w RS 16); 86 | } 87 | break; 88 | case 3: 89 | w = *(u32 *)s; 90 | *d++ = *s++; 91 | n -= 1; 92 | for (; n>=19; s+=16, d+=16, n-=16) { 93 | x = *(u32 *)(s+3); 94 | *(u32 *)(d+0) = (w LS 8) | (x RS 24); 95 | w = *(u32 *)(s+7); 96 | *(u32 *)(d+4) = (x LS 8) | (w RS 24); 97 | x = *(u32 *)(s+11); 98 | *(u32 *)(d+8) = (w LS 8) | (x RS 24); 99 | w = *(u32 *)(s+15); 100 | *(u32 *)(d+12) = (x LS 8) | (w RS 24); 101 | } 102 | break; 103 | } 104 | if (n&16) { 105 | *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; 106 | *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; 107 | *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; 108 | *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; 109 | } 110 | if (n&8) { 111 | *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; 112 | *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; 113 | } 114 | if (n&4) { 115 | *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; 116 | } 117 | if (n&2) { 118 | *d++ = *s++; *d++ = *s++; 119 | } 120 | if (n&1) { 121 | *d = *s; 122 | } 123 | return dest; 124 | #endif 125 | 126 | for (; n; n--) *d++ = *s++; 127 | return dest; 128 | } 129 | -------------------------------------------------------------------------------- /Guest/Sources/dlmalloc/src/memset.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void *memset(void *dest, int c, size_t n) 6 | { 7 | #if defined(__wasm_bulk_memory__) 8 | if (n > BULK_MEMORY_THRESHOLD) 9 | return __builtin_memset(dest, c, n); 10 | #endif 11 | unsigned char *s = dest; 12 | size_t k; 13 | 14 | /* Fill head and tail with minimal branching. Each 15 | * conditional ensures that all the subsequently used 16 | * offsets are well-defined and in the dest region. */ 17 | 18 | if (!n) return dest; 19 | s[0] = c; 20 | s[n-1] = c; 21 | if (n <= 2) return dest; 22 | s[1] = c; 23 | s[2] = c; 24 | s[n-2] = c; 25 | s[n-3] = c; 26 | if (n <= 6) return dest; 27 | s[3] = c; 28 | s[n-4] = c; 29 | if (n <= 8) return dest; 30 | 31 | /* Advance pointer to align it at a 4-byte boundary, 32 | * and truncate n to a multiple of 4. The previous code 33 | * already took care of any head/tail that get cut off 34 | * by the alignment. */ 35 | 36 | k = -(uintptr_t)s & 3; 37 | s += k; 38 | n -= k; 39 | n &= -4; 40 | 41 | #ifdef __GNUC__ 42 | typedef uint32_t __attribute__((__may_alias__)) u32; 43 | typedef uint64_t __attribute__((__may_alias__)) u64; 44 | 45 | u32 c32 = ((u32)-1)/255 * (unsigned char)c; 46 | 47 | /* In preparation to copy 32 bytes at a time, aligned on 48 | * an 8-byte bounary, fill head/tail up to 28 bytes each. 49 | * As in the initial byte-based head/tail fill, each 50 | * conditional below ensures that the subsequent offsets 51 | * are valid (e.g. !(n<=24) implies n>=28). */ 52 | 53 | *(u32 *)(s+0) = c32; 54 | *(u32 *)(s+n-4) = c32; 55 | if (n <= 8) return dest; 56 | *(u32 *)(s+4) = c32; 57 | *(u32 *)(s+8) = c32; 58 | *(u32 *)(s+n-12) = c32; 59 | *(u32 *)(s+n-8) = c32; 60 | if (n <= 24) return dest; 61 | *(u32 *)(s+12) = c32; 62 | *(u32 *)(s+16) = c32; 63 | *(u32 *)(s+20) = c32; 64 | *(u32 *)(s+24) = c32; 65 | *(u32 *)(s+n-28) = c32; 66 | *(u32 *)(s+n-24) = c32; 67 | *(u32 *)(s+n-20) = c32; 68 | *(u32 *)(s+n-16) = c32; 69 | 70 | /* Align to a multiple of 8 so we can fill 64 bits at a time, 71 | * and avoid writing the same bytes twice as much as is 72 | * practical without introducing additional branching. */ 73 | 74 | k = 24 + ((uintptr_t)s & 4); 75 | s += k; 76 | n -= k; 77 | 78 | /* If this loop is reached, 28 tail bytes have already been 79 | * filled, so any remainder when n drops below 32 can be 80 | * safely ignored. */ 81 | 82 | u64 c64 = c32 | ((u64)c32 << 32); 83 | for (; n >= 32; n-=32, s+=32) { 84 | *(u64 *)(s+0) = c64; 85 | *(u64 *)(s+8) = c64; 86 | *(u64 *)(s+16) = c64; 87 | *(u64 *)(s+24) = c64; 88 | } 89 | #else 90 | /* Pure C fallback with no aliasing violations. */ 91 | for (; n; n--, s++) *s = c; 92 | #endif 93 | 94 | return dest; 95 | } -------------------------------------------------------------------------------- /Guest/Sources/dlmalloc/src/sbrk.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include <__macro_PAGESIZE.h> 5 | 6 | void abort(void) __attribute__((noreturn)); 7 | 8 | // Bare-bones implementation of sbrk. 9 | void *sbrk(intptr_t increment) { 10 | // sbrk(0) returns the current memory size. 11 | if (increment == 0) { 12 | // The wasm spec doesn't guarantee that memory.grow of 0 always succeeds. 13 | return (void *)(__builtin_wasm_memory_size(0) * PAGESIZE); 14 | } 15 | 16 | // We only support page-size increments. 17 | if (increment % PAGESIZE != 0) { 18 | abort(); 19 | } 20 | 21 | // WebAssembly doesn't support shrinking linear memory. 22 | if (increment < 0) { 23 | abort(); 24 | } 25 | 26 | uintptr_t old = __builtin_wasm_memory_grow(0, (uintptr_t)increment / PAGESIZE); 27 | 28 | if (old == SIZE_MAX) { 29 | errno = ENOMEM; 30 | return (void *)-1; 31 | } 32 | 33 | return (void *)(old * PAGESIZE); 34 | } 35 | -------------------------------------------------------------------------------- /Guest/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ##===----------------------------------------------------------------------===## 4 | ## 5 | ## This source file is part of the Swift open source project 6 | ## 7 | ## Copyright (c) 2024 Apple Inc. and the Swift project authors 8 | ## Licensed under Apache License v2.0 with Runtime Library Exception 9 | ## 10 | ## See http://swift.org/LICENSE.txt for license information 11 | ## See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 12 | ## 13 | ##===----------------------------------------------------------------------===## 14 | 15 | set -eux 16 | 17 | bin_path=$(swift build --triple wasm32-unknown-none-wasm -c release --show-bin-path) 18 | 19 | swift build --triple wasm32-unknown-none-wasm -c release --product Plotter 20 | 21 | for n in Bass HiHat Kick Mix; do 22 | swift build --triple wasm32-unknown-none-wasm -c release --product $n 23 | 24 | cp "${bin_path}/${n}.wasm" "$HOME" 25 | done 26 | 27 | -------------------------------------------------------------------------------- /Guest/index.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | Swift Audio Workstation 13 | 15 | 25 | 26 | 27 |

Swift Audio Workstation

28 |
33 | 34 | 35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /LICENSE-vendored.md: -------------------------------------------------------------------------------- 1 | # WASI libc 2 | 3 | Code in `Sources/dlmalloc` directory is derived from WASI libc: https://github.com/WebAssembly/wasi-libc 4 | 5 | wasi-libc as a whole is multi-licensed under the 6 | Apache License v2.0 with LLVM Exceptions, the Apache License v2.0, and 7 | the MIT License. See the LICENSE-APACHE-LLVM, LICENSE-APACHE and LICENSE-MIT 8 | files, respectively, for details. 9 | 10 | Portions of this software are derived from third-party works covered by 11 | their own licenses: 12 | 13 | dlmalloc/ - CC0; see the notice in malloc.c for details 14 | emmalloc/ - MIT; see the notice in emmalloc.c for details 15 | libc-bottom-half/cloudlibc/ - BSD-2-Clause; see the LICENSE file for details 16 | libc-top-half/musl/ - MIT; see the COPYRIGHT file for details 17 | 18 | wasi-libc's changes to these files are multi-licensed under the 19 | Apache License v2.0 with LLVM Exceptions, the Apache License v2.0, 20 | the MIT License, and the original licenses of the third-party works. 21 | 22 | # WavAudioEncoder.js 23 | 24 | `.wav` format encoding implementation is derived from WavAudioEncoder.js library https://github.com/higuma/wav-audio-encoder-js and is licensed as following: 25 | 26 | The MIT License (MIT) 27 | 28 | Copyright (c) 2015 Yuji Miyane 29 | 30 | Permission is hereby granted, free of charge, to any person obtaining a copy 31 | of this software and associated documentation files (the "Software"), to deal 32 | in the Software without restriction, including without limitation the rights 33 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 34 | copies of the Software, and to permit persons to whom the Software is 35 | furnished to do so, subject to the following conditions: 36 | 37 | The above copyright notice and this permission notice shall be included in all 38 | copies or substantial portions of the Software. 39 | 40 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 42 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 43 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 44 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 45 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 46 | SOFTWARE. 47 | 48 | # Vult 49 | 50 | Code in `Sources/VultDSP` directory is derived from https://github.com/vult-dsp/vult and is licensed as following: 51 | 52 | MIT License 53 | 54 | Copyright (c) 2017 Leonardo Laguna Ruiz 55 | 56 | Permission is hereby granted, free of charge, to any person obtaining a copy 57 | of this software and associated documentation files (the "Software"), to deal 58 | in the Software without restriction, including without limitation the rights 59 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 60 | copies of the Software, and to permit persons to whom the Software is 61 | furnished to do so, subject to the following conditions: 62 | 63 | The above copyright notice and this permission notice shall be included in all 64 | copies or substantial portions of the Software. 65 | 66 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 67 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 68 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 69 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 70 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 71 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 72 | SOFTWARE. -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | 204 | 205 | ## Runtime Library Exception to the Apache 2.0 License: ## 206 | 207 | 208 | As an exception, if you use this Software to compile your source code and 209 | portions of this Software are embedded into the binary product as a result, 210 | you may redistribute such product without providing attribution as would 211 | otherwise be required by Sections 4(a), 4(b) and 4(d) of the License. 212 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swift for WebAssembly Examples 2 | 3 | A repository with a "Swift Audio Workstation" example built with Swift for WebAssembly running in the browser. 4 | 5 | This example demonstrates support for WebAssembly in latest development snapshots of the Swift toolchain, in combination 6 | with the [Embedded Swift mode](https://github.com/apple/swift/blob/main/docs/EmbeddedSwift/UserManual.md). 7 | With foundational building blocks written in Swift, it utilizes C++ interop for calling into a 8 | [DSP](https://en.wikipedia.org/wiki/Digital_signal_processing) library for synthesizing simple musical sequences. It is 9 | written with a multi-platform approach, which makes it easy to integrate into Wasm-based serverless environment or 10 | native applications and libraries. 11 | 12 | The repository is split into three packages: `Guest` with Wasm modules built with Embedded Swift, `ServerHost` that embeds these modules, and `WATExample` that demonstrates compilation of WebAssembly Text Format to binary Wasm modules using Swift. 13 | 14 | ## Requirements 15 | 16 | WebAssembly support in Swift is available for preview in latest Trunk Development (main) snapshots at 17 | [swift.org/download](https://www.swift.org/download). 18 | 19 | ### macOS 20 | 21 | 1. Install [Xcode](https://apps.apple.com/us/app/xcode/id497799835?mt=12). 22 | 2. Verify selected Xcode path by running `xcode-select -p` in the terminal. If the incorrect Xcode is selected, follow 23 | the steps provided in ["How do I select the default version of Xcode"](https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-HOW_DO_I_SELECT_THE_DEFAULT_VERSION_OF_XCODE_TO_USE_FOR_MY_COMMAND_LINE_TOOLS_) section of 24 | ["Building from the Command Line with Xcode FAQ"](https://developer.apple.com/library/archive/technotes/tn2339/_index.html). 25 | 3. Download latest `main` development snapshot, you can use [`DEVELOPMENT-SNAPSHOT-2024-04-01-a`](https://download.swift.org/development/xcode/swift-DEVELOPMENT-SNAPSHOT-2024-04-01-a/swift-DEVELOPMENT-SNAPSHOT-2024-04-01-a-osx.pkg) or a later version. 26 | 4. Run the downloaded installer: 27 | 28 | ```sh 29 | installer -target CurrentUserHomeDirectory -pkg ~/Downloads/swift-DEVELOPMENT-SNAPSHOT-2024-04-01-a-osx.pkg 30 | ``` 31 | 32 | 5. Select the newly installed snapshot: 33 | 34 | ```sh 35 | export TOOLCHAINS=$(plutil -extract CFBundleIdentifier raw \ 36 | ~/Library/Developer/Toolchains/swift-latest.xctoolchain/Info.plist) 37 | ``` 38 | 39 | ### Linux 40 | 41 | Follow Linux-specific instructions provided on [swift.org/install](https://www.swift.org/install/#linux) to install the 42 | latest development toolchain for your specific distribution. 43 | 44 | ### Docker 45 | 46 | 1. Start a docker container in a clone of this repository using the nightly swiftlang Ubuntu image, with a `/root/build` 47 | mount to the current directory: 48 | 49 | ```sh 50 | docker run --rm -it -v $(pwd):/root/build swiftlang/swift:nightly-jammy /bin/bash 51 | ``` 52 | 53 | 2. Navigate to the package directory within the container: 54 | 55 | ```sh 56 | cd /root/build 57 | ``` 58 | 59 | ## How to Build and Run 60 | 61 | Assuming you're within the cloned repository and have the latest development snapshots selected per the instructions 62 | above, build modules from the `Guest` package (this will copy `.wasm` modules to the home directory of the current user): 63 | 64 | ```sh 65 | cd Guest; ./build.sh 66 | ``` 67 | 68 | 69 | Then build and start the HTTP server: 70 | 71 | ```sh 72 | cd ../ServerHost; swift run Server 73 | ``` 74 | 75 | Open http://localhost:8080 in your browser to see the project running. Use the web interface to upload previously built 76 | `Guest` modules from the home directory. 77 | 78 | ## Contributing to this example 79 | Contributions to Swift are welcomed and encouraged! Please see the 80 | [Contributing to Swift guide](https://swift.org/contributing/). 81 | 82 | Before submitting the pull request, please make sure you have [tested your 83 | changes](https://github.com/apple/swift/blob/main/docs/ContinuousIntegration.md) 84 | and that they follow the Swift project [guidelines for contributing 85 | code](https://swift.org/contributing/#contributing-code). 86 | 87 | To be a truly great community, [Swift.org](https://swift.org/) needs to welcome 88 | developers from all walks of life, with different backgrounds, and with a wide 89 | range of experience. A diverse and friendly community will have more great 90 | ideas, more unique perspectives, and produce more great code. We will work 91 | diligently to make the Swift community welcoming to everyone. 92 | 93 | To give clarity of what is expected of our members, Swift has adopted the 94 | code of conduct defined by the Contributor Covenant. This document is used 95 | across many open source communities, and we think it articulates our values 96 | well. For more, see the [Code of Conduct](https://swift.org/code-of-conduct/). 97 | 98 | ## License 99 | 100 | See [https://swift.org/LICENSE.txt](https://swift.org/LICENSE.txt) for license information. 101 | 102 | See [`LICENSE-vendored.md`](https://github.com/apple/swift-for-wasm-examples/blob/main/LICENSE-vendored.md) for exact licenses of code vendored in this repository. 103 | -------------------------------------------------------------------------------- /ServerHost/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata/ 5 | DerivedData/ 6 | .swiftpm/configuration/registries.json 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | .netrc 9 | Public/*.wasm 10 | 11 | -------------------------------------------------------------------------------- /ServerHost/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "originHash" : "cb44da1c82932c63aa43b0ef6326cb4456306fc86cdf9670fa171ed4f61c49cc", 3 | "pins" : [ 4 | { 5 | "identity" : "async-http-client", 6 | "kind" : "remoteSourceControl", 7 | "location" : "https://github.com/swift-server/async-http-client.git", 8 | "state" : { 9 | "revision" : "11205411bb60612f0a1a04f733fa71b4fb864ab9", 10 | "version" : "1.22.1" 11 | } 12 | }, 13 | { 14 | "identity" : "hummingbird", 15 | "kind" : "remoteSourceControl", 16 | "location" : "https://github.com/hummingbird-project/hummingbird.git", 17 | "state" : { 18 | "revision" : "d4f792d209f02b26a17c0105751220da65207fb2", 19 | "version" : "2.0.1" 20 | } 21 | }, 22 | { 23 | "identity" : "swift-algorithms", 24 | "kind" : "remoteSourceControl", 25 | "location" : "https://github.com/apple/swift-algorithms.git", 26 | "state" : { 27 | "revision" : "f6919dfc309e7f1b56224378b11e28bab5bccc42", 28 | "version" : "1.2.0" 29 | } 30 | }, 31 | { 32 | "identity" : "swift-argument-parser", 33 | "kind" : "remoteSourceControl", 34 | "location" : "https://github.com/apple/swift-argument-parser", 35 | "state" : { 36 | "revision" : "41982a3656a71c768319979febd796c6fd111d5c", 37 | "version" : "1.5.0" 38 | } 39 | }, 40 | { 41 | "identity" : "swift-async-algorithms", 42 | "kind" : "remoteSourceControl", 43 | "location" : "https://github.com/apple/swift-async-algorithms.git", 44 | "state" : { 45 | "revision" : "6ae9a051f76b81cc668305ceed5b0e0a7fd93d20", 46 | "version" : "1.0.1" 47 | } 48 | }, 49 | { 50 | "identity" : "swift-atomics", 51 | "kind" : "remoteSourceControl", 52 | "location" : "https://github.com/apple/swift-atomics.git", 53 | "state" : { 54 | "revision" : "cd142fd2f64be2100422d658e7411e39489da985", 55 | "version" : "1.2.0" 56 | } 57 | }, 58 | { 59 | "identity" : "swift-collections", 60 | "kind" : "remoteSourceControl", 61 | "location" : "https://github.com/apple/swift-collections.git", 62 | "state" : { 63 | "revision" : "9bf03ff58ce34478e66aaee630e491823326fd06", 64 | "version" : "1.1.3" 65 | } 66 | }, 67 | { 68 | "identity" : "swift-distributed-tracing", 69 | "kind" : "remoteSourceControl", 70 | "location" : "https://github.com/apple/swift-distributed-tracing.git", 71 | "state" : { 72 | "revision" : "11c756c5c4d7de0eeed8595695cadd7fa107aa19", 73 | "version" : "1.1.1" 74 | } 75 | }, 76 | { 77 | "identity" : "swift-http-types", 78 | "kind" : "remoteSourceControl", 79 | "location" : "https://github.com/apple/swift-http-types", 80 | "state" : { 81 | "revision" : "ae67c8178eb46944fd85e4dc6dd970e1f3ed6ccd", 82 | "version" : "1.3.0" 83 | } 84 | }, 85 | { 86 | "identity" : "swift-log", 87 | "kind" : "remoteSourceControl", 88 | "location" : "https://github.com/apple/swift-log.git", 89 | "state" : { 90 | "revision" : "9cb486020ebf03bfa5b5df985387a14a98744537", 91 | "version" : "1.6.1" 92 | } 93 | }, 94 | { 95 | "identity" : "swift-metrics", 96 | "kind" : "remoteSourceControl", 97 | "location" : "https://github.com/apple/swift-metrics.git", 98 | "state" : { 99 | "revision" : "e0165b53d49b413dd987526b641e05e246782685", 100 | "version" : "2.5.0" 101 | } 102 | }, 103 | { 104 | "identity" : "swift-nio", 105 | "kind" : "remoteSourceControl", 106 | "location" : "https://github.com/apple/swift-nio.git", 107 | "state" : { 108 | "revision" : "9746cf80e29edfef2a39924a66731249223f42a3", 109 | "version" : "2.72.0" 110 | } 111 | }, 112 | { 113 | "identity" : "swift-nio-extras", 114 | "kind" : "remoteSourceControl", 115 | "location" : "https://github.com/apple/swift-nio-extras.git", 116 | "state" : { 117 | "revision" : "d1ead62745cc3269e482f1c51f27608057174379", 118 | "version" : "1.24.0" 119 | } 120 | }, 121 | { 122 | "identity" : "swift-nio-http2", 123 | "kind" : "remoteSourceControl", 124 | "location" : "https://github.com/apple/swift-nio-http2.git", 125 | "state" : { 126 | "revision" : "b5f7062b60e4add1e8c343ba4eb8da2e324b3a94", 127 | "version" : "1.34.0" 128 | } 129 | }, 130 | { 131 | "identity" : "swift-nio-ssl", 132 | "kind" : "remoteSourceControl", 133 | "location" : "https://github.com/apple/swift-nio-ssl.git", 134 | "state" : { 135 | "revision" : "7b84abbdcef69cc3be6573ac12440220789dcd69", 136 | "version" : "2.27.2" 137 | } 138 | }, 139 | { 140 | "identity" : "swift-nio-transport-services", 141 | "kind" : "remoteSourceControl", 142 | "location" : "https://github.com/apple/swift-nio-transport-services.git", 143 | "state" : { 144 | "revision" : "38ac8221dd20674682148d6451367f89c2652980", 145 | "version" : "1.21.0" 146 | } 147 | }, 148 | { 149 | "identity" : "swift-numerics", 150 | "kind" : "remoteSourceControl", 151 | "location" : "https://github.com/apple/swift-numerics.git", 152 | "state" : { 153 | "revision" : "0a5bc04095a675662cf24757cc0640aa2204253b", 154 | "version" : "1.0.2" 155 | } 156 | }, 157 | { 158 | "identity" : "swift-service-context", 159 | "kind" : "remoteSourceControl", 160 | "location" : "https://github.com/apple/swift-service-context.git", 161 | "state" : { 162 | "revision" : "0c62c5b4601d6c125050b5c3a97f20cce881d32b", 163 | "version" : "1.1.0" 164 | } 165 | }, 166 | { 167 | "identity" : "swift-service-lifecycle", 168 | "kind" : "remoteSourceControl", 169 | "location" : "https://github.com/swift-server/swift-service-lifecycle.git", 170 | "state" : { 171 | "revision" : "24c800fb494fbee6e42bc156dc94232dc08971af", 172 | "version" : "2.6.1" 173 | } 174 | }, 175 | { 176 | "identity" : "swift-system", 177 | "kind" : "remoteSourceControl", 178 | "location" : "https://github.com/apple/swift-system", 179 | "state" : { 180 | "revision" : "d2ba781702a1d8285419c15ee62fd734a9437ff5", 181 | "version" : "1.3.2" 182 | } 183 | }, 184 | { 185 | "identity" : "wasmkit", 186 | "kind" : "remoteSourceControl", 187 | "location" : "https://github.com/swiftwasm/WasmKit.git", 188 | "state" : { 189 | "revision" : "16a7a6351fca9f4a297cf075b3e6ade23fcf93f9", 190 | "version" : "0.1.0" 191 | } 192 | } 193 | ], 194 | "version" : 3 195 | } 196 | -------------------------------------------------------------------------------- /ServerHost/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.10 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | //===----------------------------------------------------------------------===// 5 | // 6 | // This source file is part of the Swift open source project 7 | // 8 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 9 | // Licensed under Apache License v2.0 with Runtime Library Exception 10 | // 11 | // See http://swift.org/LICENSE.txt for license information 12 | // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 13 | // 14 | //===----------------------------------------------------------------------===// 15 | 16 | import PackageDescription 17 | 18 | let package = Package( 19 | name: "ServerHost", 20 | platforms: [.macOS(.v14)], 21 | dependencies: [ 22 | .package(url: "https://github.com/apple/swift-nio.git", from: "2.72.0"), 23 | .package(url: "https://github.com/apple/swift-system.git", from: "1.3.2"), 24 | .package(url: "https://github.com/swiftwasm/WasmKit.git", from: "0.1.0"), 25 | .package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.0.0"), 26 | .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.3.0") 27 | ], 28 | targets: [ 29 | // Targets are the basic building blocks of a package, defining a module or a test suite. 30 | // Targets can depend on other targets in this package and products from dependencies. 31 | .executableTarget( 32 | name: "Server", 33 | dependencies: [ 34 | .product(name: "_NIOFileSystem", package: "swift-nio"), 35 | .product(name: "SystemPackage", package: "swift-system"), 36 | .product(name: "ArgumentParser", package: "swift-argument-parser"), 37 | .product(name: "Hummingbird", package: "hummingbird"), 38 | .product(name: "WasmKit", package: "WasmKit"), 39 | ] 40 | ), 41 | 42 | .testTarget(name: "ServerTests", 43 | dependencies: [ 44 | .byName(name: "Server"), 45 | .product(name: "HummingbirdTesting", package: "hummingbird") 46 | ] 47 | ) 48 | ] 49 | ) 50 | -------------------------------------------------------------------------------- /ServerHost/Public/.build: -------------------------------------------------------------------------------- 1 | ../../Guest/.build -------------------------------------------------------------------------------- /ServerHost/Public/Sources/JavaScript: -------------------------------------------------------------------------------- 1 | ../../../Guest/Sources/JavaScript -------------------------------------------------------------------------------- /ServerHost/Public/upload.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | Swift Audio Workstation 13 | 14 | 15 | 25 | 26 |

Audio Plugins Upload

27 |
28 | 29 | 30 |
31 | 32 | 50 | 51 | -------------------------------------------------------------------------------- /ServerHost/Sources/Server/App+Logger.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Hummingbird open source project 4 | // 5 | // Copyright (c) 2024 Adam Fowler. 6 | // Licensed under Apache License v2.0. 7 | // 8 | // See https://github.com/hummingbird-project/template/blob/main/LICENSE for license information 9 | // 10 | //===----------------------------------------------------------------------===// 11 | 12 | import Hummingbird 13 | import Logging 14 | 15 | /// Application arguments protocol. We use a protocol so we can call 16 | /// `buildApplication` inside Tests as well as in the App executable. 17 | /// Any variables added here also have to be added to `App` in App.swift and 18 | /// `TestArguments` in AppTest.swift 19 | public protocol AppArguments { 20 | var hostname: String { get } 21 | var port: Int { get } 22 | var logLevel: Logger.Level? { get } 23 | } 24 | 25 | // Request context used by application 26 | typealias AppRequestContext = BasicRequestContext 27 | 28 | /// Build application 29 | /// - Parameter arguments: application arguments 30 | public func buildApplication(_ arguments: some AppArguments) async throws -> some ApplicationProtocol { 31 | let environment = Environment() 32 | let logger = { 33 | var logger = Logger(label: "Server") 34 | logger.logLevel = 35 | arguments.logLevel ?? 36 | environment.get("LOG_LEVEL").map { Logger.Level(rawValue: $0) ?? .info } ?? 37 | .info 38 | return logger 39 | }() 40 | let router = try await makeRouter() 41 | let app = Application( 42 | router: router, 43 | configuration: .init( 44 | address: .hostname(arguments.hostname, port: arguments.port), 45 | serverName: "Server" 46 | ), 47 | logger: logger 48 | ) 49 | return app 50 | } 51 | -------------------------------------------------------------------------------- /ServerHost/Sources/Server/App+Router.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See http://swift.org/LICENSE.txt for license information 9 | // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import Hummingbird 14 | import NIOFileSystem 15 | @preconcurrency import SystemPackage 16 | 17 | let storagePath = FilePath(#filePath) 18 | .removingLastComponent() 19 | .removingLastComponent() 20 | .removingLastComponent() 21 | .appending("Public") 22 | 23 | private let contentTypes = [ 24 | "html": "text/html", 25 | "css": "text/css", 26 | "js": "text/javascript", 27 | "wasm": "application/wasm", 28 | ] 29 | 30 | private func serveFile(path: FilePath) async throws -> Response { 31 | var headers = HTTPFields(dictionaryLiteral: 32 | (.contentType, contentTypes[path.extension ?? ""] ?? "application/octet-stream") 33 | ) 34 | if let info = try await FileSystem.shared.info(forFileAt: path) { 35 | headers[.contentLength] = String(info.size) 36 | } 37 | 38 | return Response( 39 | status: .ok, 40 | headers: headers, 41 | body: ResponseBody { writer in 42 | try await FileSystem.shared.withFileHandle(forReadingAt: path) { 43 | for try await chunk in $0.readChunks() { 44 | try await writer.write(chunk) 45 | } 46 | } 47 | 48 | try await writer.finish(nil) 49 | }) 50 | } 51 | 52 | enum UploadError: Error { 53 | case invalidFileName 54 | } 55 | 56 | func makeRouter() async throws -> Router { 57 | Router(context: BasicRequestContext.self) 58 | .get("/") { _, _ in 59 | Response( 60 | status: .temporaryRedirect, 61 | headers: [.location: "/public/index.html"] 62 | ) 63 | } 64 | 65 | .get("/public/index.html") { _, _ in 66 | let wasmModules = try await discoverModules( 67 | directory: storagePath, 68 | root: storagePath 69 | ) 70 | 71 | return IndexPage(modules: wasmModules) 72 | } 73 | 74 | .post("/wasm-module/:name") { req, ctx in 75 | guard let fileName = ctx.parameters.get("name") 76 | else { throw UploadError.invalidFileName } 77 | 78 | try await FileSystem.shared.withFileHandle( 79 | forWritingAt: storagePath.appending(String(fileName)), 80 | options: .newFile(replaceExisting: true) 81 | ) { 82 | var offset: Int64 = 0 83 | for try await buffer in req.body { 84 | let count = buffer.readableBytes 85 | try await $0.write(contentsOf: buffer, toAbsoluteOffset: offset) 86 | offset += Int64(count) 87 | } 88 | } 89 | 90 | return HTTPResponse.Status.ok 91 | } 92 | 93 | .get("/public/**") { req, ctx in 94 | let path = ctx.parameters.getCatchAll().joined(separator: "/") 95 | 96 | return try await serveFile(path: storagePath.appending(path)) 97 | } 98 | 99 | .get("/mix") { _, _ in 100 | let wasmModules = try await discoverModules( 101 | directory: storagePath, 102 | root: storagePath 103 | ) 104 | 105 | return try MixedOutput(modules: wasmModules) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /ServerHost/Sources/Server/App.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Hummingbird open source project 4 | // 5 | // Copyright (c) 2024 Adam Fowler. 6 | // Licensed under Apache License v2.0. 7 | // 8 | // See https://github.com/hummingbird-project/template/blob/main/LICENSE for license information 9 | // 10 | //===----------------------------------------------------------------------===// 11 | 12 | import ArgumentParser 13 | import Hummingbird 14 | import Logging 15 | 16 | @main 17 | struct App: AsyncParsableCommand, AppArguments { 18 | @Option(name: .shortAndLong) 19 | var hostname: String = "127.0.0.1" 20 | 21 | @Option(name: .shortAndLong) 22 | var port: Int = 8080 23 | 24 | @Option(name: .shortAndLong) 25 | var logLevel: Logger.Level? 26 | 27 | func run() async throws { 28 | let app = try await buildApplication(self) 29 | try await app.runService() 30 | } 31 | } 32 | 33 | /// Extend `Logger.Level` so it can be used as an argument 34 | #if hasFeature(RetroactiveAttribute) 35 | extension Logger.Level: @retroactive ExpressibleByArgument {} 36 | #else 37 | extension Logger.Level: ExpressibleByArgument {} 38 | #endif 39 | -------------------------------------------------------------------------------- /ServerHost/Sources/Server/IndexPage.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See http://swift.org/LICENSE.txt for license information 9 | // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import Foundation 14 | import Hummingbird 15 | import _NIOFileSystem 16 | @preconcurrency import SystemPackage 17 | 18 | private func serveHTML(_ string: String) -> Response { 19 | .init( 20 | status: .ok, 21 | headers: .init(dictionaryLiteral: (.contentType, "text/html"), (.contentLength, "\(string.utf8.count)")), 22 | body: .init(byteBuffer: .init(string: string)) 23 | ) 24 | } 25 | 26 | struct IndexPage: ResponseGenerator, Sendable { 27 | struct Module: Sendable { 28 | let name: String 29 | let absolutePath: FilePath 30 | let relativePath: FilePath 31 | } 32 | 33 | var modules: [Module] = [] 34 | 35 | var modulesList: String { 36 | if self.modules.isEmpty { 37 | """ 38 |

Upload Wasm plugins to get started

39 | """ 40 | } else { 41 | """ 42 | \(self.modules.sorted(using: KeyPathComparator(\.name, order: .forward)).map { module in 43 | """ 44 |

\(module.name)

45 |
50 | 51 | 52 |
53 | """ 54 | }.joined(separator: "\n")) 55 | 56 |

Mix

57 |
61 | 62 | 63 |
64 | """ 65 | } 66 | } 67 | 68 | func response(from request: Request, context: some RequestContext) throws -> Response { 69 | serveHTML( 70 | """ 71 | 72 | 73 | 74 | Swift Audio Workstation 75 | 77 | 90 | 91 | 92 | \(self.modulesList) 93 | 94 | 95 | """ 96 | ) 97 | } 98 | } 99 | 100 | func discoverModules(directory: FilePath, root: FilePath) async throws -> [IndexPage.Module] { 101 | try await FileSystem.shared.withDirectoryHandle(atPath: directory) { 102 | var modules = [IndexPage.Module]() 103 | let dirContents = $0.listContents() 104 | 105 | for try await module in dirContents where module.type == .regular && module.path.isSynthModule { 106 | let absolutePath = module.path 107 | var relativePath = module.path 108 | _ = relativePath.removePrefix(root) 109 | modules.append(.init( 110 | name: module.path.lastComponent?.stem ?? "Module", 111 | absolutePath: absolutePath, 112 | relativePath: relativePath 113 | )) 114 | } 115 | 116 | return modules 117 | } 118 | } 119 | 120 | extension FilePath { 121 | var isSynthModule: Bool { 122 | self.extension == "wasm" && self.stem != "Plotter" 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /ServerHost/Sources/Server/MixedOutput.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See http://swift.org/LICENSE.txt for license information 9 | // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import Hummingbird 14 | import WasmKit 15 | 16 | struct MixedOutput: ResponseGenerator { 17 | init(modules: [IndexPage.Module]) throws { 18 | self.modules = try modules.map { 19 | try parseWasm(filePath: $0.absolutePath) 20 | } 21 | } 22 | 23 | var modules: [Module] 24 | 25 | func response(from request: Request, context: some RequestContext) throws -> Response { 26 | var samples = [Float32]() 27 | 28 | let engine = Engine() 29 | let store = Store(engine: engine) 30 | var moduleInstances = [Instance]() 31 | 32 | // Instantiate each Wasm module 33 | for (moduleIndex, module) in modules.enumerated() { 34 | let encode = ExternalValue.function(.init(store: store, type: .init( 35 | parameters: [.i32, .i32, .i32] 36 | )) { caller, args in 37 | let start = args[1].i32 38 | let byteCount = args[2].i32 39 | 40 | // Read audio buffer from Wasm linear memory. 41 | moduleInstances[moduleIndex].exports[memory: "memory"]!.data[ 42 | Int(start)..