webaudio for tauri

This commit is contained in:
Vasilii Milovidov
2023-09-18 14:18:00 +04:00
parent 9e27c0fe2c
commit 081f93cb79
9 changed files with 1122 additions and 36 deletions
+1
View File
@@ -7,3 +7,4 @@ This program is free software: you can redistribute it and/or modify it under th
export * from './midibridge.mjs';
export * from './utils.mjs';
export * from './oscbridge.mjs';
export * from './webaudiobridge.mjs';
+1
View File
@@ -22,6 +22,7 @@
"url": "https://github.com/tidalcycles/strudel/issues"
},
"dependencies": {
"@strudel.cycles/webaudio": "^0.9.0",
"@strudel.cycles/core": "workspace:*",
"@tauri-apps/api": "^1.4.0"
},
+109
View File
@@ -0,0 +1,109 @@
import { Invoke } from './utils.mjs';
import {duration, isNote, midiToFreq, noteToMidi, Pattern} from '@strudel.cycles/core';
import {getAudioContext} from "@strudel.cycles/webaudio";
export const desktopAudio = async (value, deadline, hapDuration) => {
const ac = getAudioContext();
if (typeof value !== 'object') {
throw new Error(
`expected hap.value to be an object, but got "${value}". Hint: append .note() or .s() to the end`,
'error',
);
}
let t = ac.currentTime + deadline;
let {
note = "C3",
s = 'triangle',
bank = '',
source,
gain = 0.8,
// low pass
cutoff = 8000,
resonance = 1,
// high pass
hcutoff = 0,
hresonance = 1,
// band pass
bandf = 0,
bandq = 1,
//
coarse,
crush,
shape,
pan,
vowel,
delay = 0,
delayfeedback = 0.5,
delaytime = 0.25,
orbit = 1,
room,
size = 2,
velocity = 1,
analyze, // analyser wet
fft = 8, // fftSize 0 - 10
speed = 1, // sample playback speed
begin = 0,
end = 1,
loop = 0,
loopBegin = 0,
loopEnd = 1,
} = value;
console.log(value);
value.duration = hapDuration;
if (isNote(note)) {
note = noteToMidi(note);
}
if (delay !== 0) {
delay = Math.abs(delay);
delayfeedback = Math.abs(delayfeedback);
delaytime = Math.abs(delaytime);
}
const loop_packaged = [loop, loopBegin, loopEnd];
const delay_packaged = [delay, delayfeedback, delaytime];
const offset = (t - getAudioContext().currentTime) * 1000;
const roundedOffset = Math.round(offset);
const messagesfromjs = [];
messagesfromjs.push({
note: midiToFreq(note),
offset: roundedOffset,
waveform: s,
bank: bank,
cutoff: cutoff,
resonance: resonance,
hcutoff: hcutoff,
hresonance: hresonance,
bandf: bandf,
bandq: bandq,
duration: hapDuration,
velocity: velocity,
delay: delay_packaged,
speed: speed,
begin: begin,
end: end,
loop_packaged: loop_packaged,
});
if (messagesfromjs.length) {
setTimeout(() => {
Invoke('sendwebaudio', { messagesfromjs });
});
}
}
const hap2value = (hap) => {
hap.ensureObjectValue();
return { ...hap.value, velocity: hap.context.velocity };
};
export const webaudioDesktopOutputTrigger = (t, hap, ct, cps) => desktopAudio(hap2value(hap), t - ct, hap.duration / cps, cps);
export const webaudioDesktopOutput = (hap, deadline, hapDuration) => desktopAudio(hap2value(hap), deadline, hapDuration);
Pattern.prototype.webaudio = function () {
return this.onTrigger(webaudioDesktopOutputTrigger);
};
+22
View File
@@ -1,5 +1,9 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
@@ -181,6 +185,9 @@ importers:
'@strudel.cycles/core':
specifier: workspace:*
version: link:../core
'@strudel.cycles/webaudio':
specifier: ^0.9.0
version: link:../webaudio
'@tauri-apps/api':
specifier: ^1.4.0
version: 1.4.0
@@ -1426,6 +1433,7 @@ packages:
/@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.21.5):
resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==}
engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
@@ -1441,6 +1449,7 @@ packages:
/@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.21.5):
resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==}
engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
@@ -1454,6 +1463,7 @@ packages:
/@babel/plugin-proposal-class-static-block@7.20.7(@babel/core@7.21.5):
resolution: {integrity: sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==}
engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-static-block instead.
peerDependencies:
'@babel/core': ^7.12.0
dependencies:
@@ -1468,6 +1478,7 @@ packages:
/@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.21.5):
resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==}
engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-dynamic-import instead.
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
@@ -1479,6 +1490,7 @@ packages:
/@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.21.5):
resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==}
engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead.
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
@@ -1490,6 +1502,7 @@ packages:
/@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.21.5):
resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==}
engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-json-strings instead.
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
@@ -1501,6 +1514,7 @@ packages:
/@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.21.5):
resolution: {integrity: sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==}
engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-logical-assignment-operators instead.
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
@@ -1512,6 +1526,7 @@ packages:
/@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.21.5):
resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==}
engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
@@ -1523,6 +1538,7 @@ packages:
/@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.21.5):
resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==}
engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
@@ -1534,6 +1550,7 @@ packages:
/@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.21.5):
resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==}
engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
@@ -1548,6 +1565,7 @@ packages:
/@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.21.5):
resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==}
engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
@@ -1559,6 +1577,7 @@ packages:
/@babel/plugin-proposal-optional-chaining@7.20.7(@babel/core@7.21.5):
resolution: {integrity: sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==}
engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
@@ -1571,6 +1590,7 @@ packages:
/@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.21.5):
resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==}
engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
@@ -1584,6 +1604,7 @@ packages:
/@babel/plugin-proposal-private-property-in-object@7.20.5(@babel/core@7.21.5):
resolution: {integrity: sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==}
engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
@@ -1599,6 +1620,7 @@ packages:
/@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.21.5):
resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==}
engines: {node: '>=4'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
+692 -13
View File
@@ -104,8 +104,21 @@ dependencies = [
"tauri",
"tauri-build",
"tokio",
"web-audio-api",
]
[[package]]
name = "arc-swap"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
[[package]]
name = "arrayvec"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "atk"
version = "0.15.1"
@@ -163,6 +176,26 @@ version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
[[package]]
name = "bindgen"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"lazy_static",
"lazycell",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn 1.0.109",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -221,6 +254,12 @@ version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "byte-slice-cast"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c"
[[package]]
name = "bytemuck"
version = "1.13.1"
@@ -239,6 +278,12 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
[[package]]
name = "cache-padded"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21"
[[package]]
name = "cairo-rs"
version = "0.15.12"
@@ -278,6 +323,9 @@ name = "cc"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
dependencies = [
"jobserver",
]
[[package]]
name = "cesu8"
@@ -285,6 +333,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfb"
version = "0.7.3"
@@ -334,6 +391,17 @@ dependencies = [
"winapi",
]
[[package]]
name = "clang-sys"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "cocoa"
version = "0.24.1"
@@ -393,10 +461,16 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [
"core-foundation-sys",
"core-foundation-sys 0.8.4",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
[[package]]
name = "core-foundation-sys"
version = "0.8.4"
@@ -427,6 +501,26 @@ dependencies = [
"libc",
]
[[package]]
name = "coreaudio-rs"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb17e2d1795b1996419648915df94bc7103c28f7b48062d7acf4652fc371b2ff"
dependencies = [
"bitflags",
"core-foundation-sys 0.6.2",
"coreaudio-sys",
]
[[package]]
name = "coreaudio-sys"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f034b2258e6c4ade2f73bf87b21047567fb913ee9550837c2316d139b0262b24"
dependencies = [
"bindgen",
]
[[package]]
name = "coremidi"
version = "0.6.0"
@@ -434,7 +528,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a7847ca018a67204508b77cb9e6de670125075f7464fff5f673023378fa34f5"
dependencies = [
"core-foundation",
"core-foundation-sys",
"core-foundation-sys 0.8.4",
"coremidi-sys",
]
@@ -444,7 +538,32 @@ version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79a6deed0c97b2d40abbab77e4c97f81d71e162600423382c277dd640019116c"
dependencies = [
"core-foundation-sys",
"core-foundation-sys 0.8.4",
]
[[package]]
name = "cpal"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d959d90e938c5493000514b446987c07aed46c668faaa7d34d6c7a67b1a578c"
dependencies = [
"alsa",
"core-foundation-sys 0.8.4",
"coreaudio-rs",
"dasp_sample",
"jni 0.19.0",
"js-sys",
"libc",
"mach2",
"ndk 0.7.0",
"ndk-context",
"oboe",
"once_cell",
"parking_lot",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows 0.46.0",
]
[[package]]
@@ -465,6 +584,47 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "creek"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b01a32e142cd462c493f706a208780b3f90bed74b55c4ee9f6a67d3f4fe292bd"
dependencies = [
"creek-core",
"creek-decode-symphonia",
"creek-encode-wav",
]
[[package]]
name = "creek-core"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "324fdebf340780c68b62d526f524a4cad41495db651d9c1333d2930ba189d6e4"
dependencies = [
"rtrb",
]
[[package]]
name = "creek-decode-symphonia"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8371cf1deee7e3df88125c6c54e95e7966ba62e508b041db238f48a383119706"
dependencies = [
"creek-core",
"log",
"symphonia",
]
[[package]]
name = "creek-encode-wav"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063e2422d455bb48879d04b0787b1e697e24c6fd3f3a3fa54554636e1595f316"
dependencies = [
"byte-slice-cast",
"creek-core",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.8"
@@ -566,6 +726,12 @@ dependencies = [
"syn 2.0.18",
]
[[package]]
name = "dasp_sample"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
[[package]]
name = "derive_more"
version = "0.99.17"
@@ -736,6 +902,12 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "float_eq"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28a80e3145d8ad11ba0995949bbcf48b9df2be62772b3d351ef017dff6ecb853"
[[package]]
name = "fnv"
version = "1.0.7"
@@ -1187,6 +1359,23 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hound"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d13cdbd5dbb29f9c88095bbdc2590c9cba0d0a1269b983fef6b2cdd7e9f4db1"
[[package]]
name = "hrtf"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73088c4a5d7c9d21ee942a54611696f247c4bafc85e9261bf8c409b6857e75be"
dependencies = [
"byteorder",
"rubato 0.10.1",
"rustfft",
]
[[package]]
name = "html5ever"
version = "0.25.2"
@@ -1225,7 +1414,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"core-foundation-sys 0.8.4",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
@@ -1372,6 +1561,20 @@ dependencies = [
"system-deps 5.0.0",
]
[[package]]
name = "jni"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec"
dependencies = [
"cesu8",
"combine",
"jni-sys",
"log",
"thiserror",
"walkdir",
]
[[package]]
name = "jni"
version = "0.20.0"
@@ -1392,6 +1595,15 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "jobserver"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
dependencies = [
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.64"
@@ -1431,12 +1643,28 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.146"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
[[package]]
name = "libloading"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
]
[[package]]
name = "line-wrap"
version = "0.1.1"
@@ -1452,6 +1680,12 @@ version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "llq"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22edcb39a6fc7e511be7ba578a719af09125391ecde44e0bd61ad3c8e003a4a3"
[[package]]
name = "lock_api"
version = "0.4.10"
@@ -1489,6 +1723,15 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "mach2"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8"
dependencies = [
"libc",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
@@ -1593,11 +1836,25 @@ checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4"
dependencies = [
"bitflags",
"jni-sys",
"ndk-sys",
"ndk-sys 0.3.0",
"num_enum",
"thiserror",
]
[[package]]
name = "ndk"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0"
dependencies = [
"bitflags",
"jni-sys",
"ndk-sys 0.4.1+23.1.7779620",
"num_enum",
"raw-window-handle",
"thiserror",
]
[[package]]
name = "ndk-context"
version = "0.1.1"
@@ -1613,6 +1870,15 @@ dependencies = [
"jni-sys",
]
[[package]]
name = "ndk-sys"
version = "0.4.1+23.1.7779620"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3"
dependencies = [
"jni-sys",
]
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
@@ -1656,6 +1922,26 @@ dependencies = [
"winapi",
]
[[package]]
name = "num-complex"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
dependencies = [
"num-traits",
]
[[package]]
name = "num-derive"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "num-integer"
version = "0.1.45"
@@ -1754,6 +2040,29 @@ dependencies = [
"memchr",
]
[[package]]
name = "oboe"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8868cc237ee02e2d9618539a23a8d228b9bb3fc2e7a5b11eed3831de77c395d0"
dependencies = [
"jni 0.20.0",
"ndk 0.7.0",
"ndk-context",
"num-derive",
"num-traits",
"oboe-sys",
]
[[package]]
name = "oboe-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f44155e7fb718d3cfddcf70690b2b51ac4412f347cd9e4fbe511abe9cd7b5f2"
dependencies = [
"cc",
]
[[package]]
name = "once_cell"
version = "1.18.0"
@@ -1811,9 +2120,15 @@ dependencies = [
"libc",
"redox_syscall 0.3.5",
"smallvec",
"windows-targets",
"windows-targets 0.48.0",
]
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "percent-encoding"
version = "2.3.0"
@@ -1930,6 +2245,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "piston-float"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad78bf43dcf80e8f950c92b84f938a0fc7590b7f6866fbcbeca781609c115590"
[[package]]
name = "pkg-config"
version = "0.3.27"
@@ -1975,6 +2296,15 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "primal-check"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9df7f93fd637f083201473dab4fee2db4c429d32e55e3299980ab3957ab916a0"
dependencies = [
"num-integer",
]
[[package]]
name = "proc-macro-crate"
version = "1.3.1"
@@ -2129,6 +2459,24 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
[[package]]
name = "realfft"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7695c87f31dc3644760f23fb59a3fed47659703abf76cf2d111f03b9e712342"
dependencies = [
"rustfft",
]
[[package]]
name = "realfft"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953d9f7e5cdd80963547b456251296efc2626ed4e3cbf36c869d9564e0220571"
dependencies = [
"rustfft",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
@@ -2200,12 +2548,52 @@ dependencies = [
"nom",
]
[[package]]
name = "rtrb"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99e704dd104faf2326a320140f70f0b736d607c1caa1b1748a6c568a79819109"
dependencies = [
"cache-padded",
]
[[package]]
name = "rubato"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "610bbefcfef7f43cbe275995b6077b74f34480efce293c30327bf44fdad871ed"
dependencies = [
"log",
"num-complex",
"num-integer",
"num-traits",
"realfft 2.0.1",
]
[[package]]
name = "rubato"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6dd52e80cfc21894deadf554a5673002938ae4625f7a283e536f9cf7c17b0d5"
dependencies = [
"num-complex",
"num-integer",
"num-traits",
"realfft 3.3.0",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc_version"
version = "0.4.0"
@@ -2215,6 +2603,21 @@ dependencies = [
"semver",
]
[[package]]
name = "rustfft"
version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e17d4f6cbdb180c9f4b2a26bbf01c4e647f1e1dea22fe8eb9db54198b32f9434"
dependencies = [
"num-complex",
"num-integer",
"num-traits",
"primal-check",
"strength_reduce",
"transpose",
"version_check",
]
[[package]]
name = "rustix"
version = "0.37.20"
@@ -2428,6 +2831,12 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "shlex"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380"
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
@@ -2460,9 +2869,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.10.0"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
[[package]]
name = "socket2"
@@ -2517,6 +2926,12 @@ dependencies = [
"loom",
]
[[package]]
name = "strength_reduce"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82"
[[package]]
name = "string_cache"
version = "0.8.7"
@@ -2549,6 +2964,189 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "symphonia"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62e48dba70095f265fdb269b99619b95d04c89e619538138383e63310b14d941"
dependencies = [
"lazy_static",
"symphonia-bundle-flac",
"symphonia-bundle-mp3",
"symphonia-codec-aac",
"symphonia-codec-adpcm",
"symphonia-codec-alac",
"symphonia-codec-pcm",
"symphonia-codec-vorbis",
"symphonia-core",
"symphonia-format-isomp4",
"symphonia-format-mkv",
"symphonia-format-ogg",
"symphonia-format-wav",
"symphonia-metadata",
]
[[package]]
name = "symphonia-bundle-flac"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f23b0482a7cb18fcdf9981ab0b78df800ef0080187d294650023c462439058d"
dependencies = [
"log",
"symphonia-core",
"symphonia-metadata",
"symphonia-utils-xiph",
]
[[package]]
name = "symphonia-bundle-mp3"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f31d7fece546f1e6973011a9eceae948133bbd18fd3d52f6073b1e38ae6368a"
dependencies = [
"bitflags",
"lazy_static",
"log",
"symphonia-core",
"symphonia-metadata",
]
[[package]]
name = "symphonia-codec-aac"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68bdd75b25ce4b84b12a4bd20bfea2460c2dbd7fc1d227ef5533504d3168109d"
dependencies = [
"lazy_static",
"log",
"symphonia-core",
]
[[package]]
name = "symphonia-codec-adpcm"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "870e7dc1865d818c7b6318879d060553a73a3b2a3b8443dff90910f10ac41150"
dependencies = [
"log",
"symphonia-core",
]
[[package]]
name = "symphonia-codec-alac"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a27e8763d1c9eff666faf903e73a99d4de2f7a93fca4e3c214c1d68432903b9"
dependencies = [
"log",
"symphonia-core",
]
[[package]]
name = "symphonia-codec-pcm"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47f1fbd220a06a641c8ce2ddad10f5ef6ee5cc0c54d9044d25d43b0d3119deaa"
dependencies = [
"log",
"symphonia-core",
]
[[package]]
name = "symphonia-codec-vorbis"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3953397e3506aa01350c4205817e4f95b58d476877a42f0458d07b665749e203"
dependencies = [
"log",
"symphonia-core",
"symphonia-utils-xiph",
]
[[package]]
name = "symphonia-core"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c73eb88fee79705268cc7b742c7bc93a7b76e092ab751d0833866970754142"
dependencies = [
"arrayvec",
"bitflags",
"bytemuck",
"lazy_static",
"log",
]
[[package]]
name = "symphonia-format-isomp4"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdf14bae5cf352032416bc64151e5d6242d29d33cbf3238513b44d4427a1efb"
dependencies = [
"encoding_rs",
"log",
"symphonia-core",
"symphonia-metadata",
"symphonia-utils-xiph",
]
[[package]]
name = "symphonia-format-mkv"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5c61dfc851ad25d4043d8c231d8617e8f7cd02a6cc0edad21ade21848d58895"
dependencies = [
"lazy_static",
"log",
"symphonia-core",
"symphonia-metadata",
"symphonia-utils-xiph",
]
[[package]]
name = "symphonia-format-ogg"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bf1a00ccd11452d44048a0368828040f778ae650418dbd9d8765b7ee2574c8d"
dependencies = [
"log",
"symphonia-core",
"symphonia-metadata",
"symphonia-utils-xiph",
]
[[package]]
name = "symphonia-format-wav"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da76614728fa27c003bdcdfbac51396bd8fcbf94c95fe8e62f1d2bac58ef03a4"
dependencies = [
"log",
"symphonia-core",
"symphonia-metadata",
]
[[package]]
name = "symphonia-metadata"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89c3e1937e31d0e068bbe829f66b2f2bfaa28d056365279e0ef897172c3320c0"
dependencies = [
"encoding_rs",
"lazy_static",
"log",
"symphonia-core",
]
[[package]]
name = "symphonia-utils-xiph"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a450ca645b80d69aff8b35576cbfdc7f20940b29998202aab910045714c951f8"
dependencies = [
"symphonia-core",
"symphonia-metadata",
]
[[package]]
name = "syn"
version = "1.0.109"
@@ -2622,13 +3220,13 @@ dependencies = [
"gtk",
"image",
"instant",
"jni",
"jni 0.20.0",
"lazy_static",
"libc",
"log",
"ndk",
"ndk 0.6.0",
"ndk-context",
"ndk-sys",
"ndk-sys 0.3.0",
"objc",
"once_cell",
"parking_lot",
@@ -3091,6 +3689,16 @@ dependencies = [
"tracing-log",
]
[[package]]
name = "transpose"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6522d49d03727ffb138ae4cbc1283d3774f0d10aa7f9bf52e6784c45daf9b23"
dependencies = [
"num-integer",
"strength_reduce",
]
[[package]]
name = "treediff"
version = "4.0.2"
@@ -3166,6 +3774,15 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "vecmath"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "956ae1e0d85bca567dee1dcf87fb1ca2e792792f66f87dced8381f99cd91156a"
dependencies = [
"piston-float",
]
[[package]]
name = "version-compare"
version = "0.0.11"
@@ -3251,6 +3868,18 @@ dependencies = [
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.87"
@@ -3280,6 +3909,32 @@ version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "web-audio-api"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b600725f86c3caa0f8823ff5e3c42aecbdfcd4a390db2be9278eb06d16a98c1a"
dependencies = [
"arc-swap",
"arrayvec",
"cpal",
"creek",
"crossbeam-channel",
"dasp_sample",
"float_eq",
"hound",
"hrtf",
"llq",
"log",
"num-complex",
"realfft 3.3.0",
"rubato 0.14.1",
"rustc-hash",
"smallvec",
"symphonia",
"vecmath",
]
[[package]]
name = "web-sys"
version = "0.3.64"
@@ -3435,13 +4090,22 @@ dependencies = [
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
dependencies = [
"windows-targets",
"windows-targets 0.48.0",
]
[[package]]
@@ -3476,7 +4140,22 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
"windows-targets 0.48.0",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]]
+1
View File
@@ -21,6 +21,7 @@ tauri = { version = "1.4.0", features = ["fs-all"] }
midir = "0.9.1"
tokio = { version = "1.29.0", features = ["full"] }
rosc = "0.10.1"
web-audio-api = "0.33.0"
[features]
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
+30 -22
View File
@@ -4,6 +4,8 @@
mod midibridge;
mod oscbridge;
mod loggerbridge;
mod webaudiobridge;
use std::sync::Arc;
use loggerbridge::Logger;
@@ -21,27 +23,33 @@ fn main() {
let (async_output_transmitter_midi, async_output_receiver_midi) = mpsc::channel(1);
let (async_input_transmitter_osc, async_input_receiver_osc) = mpsc::channel(1);
let (async_output_transmitter_osc, async_output_receiver_osc) = mpsc::channel(1);
let (async_input_transmitter_webaudio, async_input_receiver_webaudio) = mpsc::channel(1);
let (async_output_transmitter_webaudio, async_output_receiver_webaudio) = mpsc::channel(1);
tauri::Builder
::default()
.manage(midibridge::AsyncInputTransmit {
inner: Mutex::new(async_input_transmitter_midi),
})
.manage(oscbridge::AsyncInputTransmit {
inner: Mutex::new(async_input_transmitter_osc),
})
.invoke_handler(tauri::generate_handler![midibridge::sendmidi, oscbridge::sendosc])
.setup(|app| {
let window = Arc::new(app.get_window("main").unwrap());
let logger = Logger { window };
midibridge::init(
logger.clone(),
async_input_receiver_midi,
async_output_receiver_midi,
async_output_transmitter_midi
);
oscbridge::init(logger, async_input_receiver_osc, async_output_receiver_osc, async_output_transmitter_osc);
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
::default()
.manage(midibridge::AsyncInputTransmit {
inner: Mutex::new(async_input_transmitter_midi),
})
.manage(oscbridge::AsyncInputTransmit {
inner: Mutex::new(async_input_transmitter_osc),
})
.manage(webaudiobridge::AsyncInputTransmitWebAudio {
inner: Mutex::new(async_input_transmitter_webaudio),
})
.invoke_handler(tauri::generate_handler![midibridge::sendmidi, oscbridge::sendosc, webaudiobridge::sendwebaudio])
.setup(|app| {
let window = Arc::new(app.get_window("main").unwrap());
let logger = Logger { window };
midibridge::init(
logger.clone(),
async_input_receiver_midi,
async_output_receiver_midi,
async_output_transmitter_midi
);
oscbridge::init(logger, async_input_receiver_osc, async_output_receiver_osc, async_output_transmitter_osc);
webaudiobridge::init(async_input_receiver_webaudio, async_output_receiver_webaudio, async_output_transmitter_webaudio);
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
+264
View File
@@ -0,0 +1,264 @@
use std::fs::File;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::{ mpsc, Mutex };
use tokio::time::Instant;
use serde::Deserialize;
use std::thread::sleep;
use web_audio_api::context::{AudioContext, AudioContextLatencyCategory, AudioContextOptions, BaseAudioContext};
use web_audio_api::node::{AudioNode, AudioScheduledSourceNode, BiquadFilterNode, GainNode, OscillatorType};
use web_audio_api::node::BiquadFilterType::{Bandpass, Highpass, Lowpass};
#[derive(Clone, Copy, Debug)]
pub struct Delay {
pub wet: f64,
pub delay_time: f64,
pub feedback: f64,
}
#[derive(Debug)]
pub struct WebAudioMessage {
pub note: f32,
pub instant: Instant,
pub offset: f64,
pub waveform: String,
pub bank: String,
pub cutoff: f32,
pub resonance: f32,
pub hcutoff: f32,
pub hresonance: f32,
pub bandf: f32,
pub bandq: f32,
pub duration: f64,
pub velocity: f32,
pub delay: Delay,
pub speed: f32,
pub begin: f64,
pub end: f64,
pub loop_packaged: (u8, f64, f64),
}
pub struct AsyncInputTransmitWebAudio {
pub inner: Mutex<mpsc::Sender<Vec<WebAudioMessage>>>,
}
pub fn init(
async_input_receiver: mpsc::Receiver<Vec<WebAudioMessage>>,
mut async_output_receiver: mpsc::Receiver<Vec<WebAudioMessage>>,
async_output_transmitter: mpsc::Sender<Vec<WebAudioMessage>>
) {
tauri::async_runtime::spawn(async move { async_process_model(async_input_receiver, async_output_transmitter).await });
let message_queue: Arc<Mutex<Vec<WebAudioMessage>>> = Arc::new(Mutex::new(Vec::new()));
/* ...........................................................
Listen For incoming messages and add to queue
............................................................*/
let message_queue_clone = Arc::clone(&message_queue);
tauri::async_runtime::spawn(async move {
loop {
if let Some(package) = async_output_receiver.recv().await {
let mut message_queue = message_queue_clone.lock().await;
let messages = package;
for message in messages {
(*message_queue).push(message);
}
}
}
});
let message_queue_clone = Arc::clone(&message_queue);
tauri::async_runtime::spawn(async move {
/* ...........................................................
Prepare audio context
............................................................*/
let latency_hint = match std::env::var("WEB_AUDIO_LATENCY").as_deref() {
Ok("playback") => AudioContextLatencyCategory::Playback,
_ => AudioContextLatencyCategory::default(),
};
let mut audio_context = AudioContext::new(AudioContextOptions {
latency_hint,
..AudioContextOptions::default()
});
/* ...........................................................
Process queued messages
............................................................*/
loop {
let mut message_queue = message_queue_clone.lock().await;
// Iterate over each message, play and remove messages when they are ready
message_queue.retain(|message| {
if message.instant.elapsed().as_millis() < message.offset as u128 {
return true;
};
superdough(message.clone(), &mut audio_context);
return false;
});
sleep(Duration::from_millis(1));
}
});
}
pub async fn async_process_model(
mut input_reciever: mpsc::Receiver<Vec<WebAudioMessage>>,
output_transmitter: mpsc::Sender<Vec<WebAudioMessage>>
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
while let Some(input) = input_reciever.recv().await {
let output = input;
output_transmitter.send(output).await?;
}
Ok(())
}
#[derive(Deserialize)]
pub struct MessageFromJS {
note: f32,
offset: f64,
waveform: String,
bank: String,
cutoff: f32,
resonance: f32,
hcutoff: f32,
hresonance: f32,
bandf: f32,
bandq: f32,
duration: f64,
velocity: f32,
delay: Vec<f64>,
speed: f32,
begin: f64,
end: f64,
loop_packaged: (u8, f64, f64),
}
// Called from JS
#[tauri::command]
pub async fn sendwebaudio(
messagesfromjs: Vec<MessageFromJS>,
state: tauri::State<'_, AsyncInputTransmitWebAudio>
) -> Result<(), String> {
let async_proc_input_tx = state.inner.lock().await;
let mut messages_to_process: Vec<WebAudioMessage> = Vec::new();
for m in messagesfromjs {
let message_to_process = WebAudioMessage {
note: m.note,
instant: Instant::now(),
offset: m.offset,
waveform: m.waveform,
bank: m.bank,
cutoff: m.cutoff,
resonance: m.resonance,
hcutoff: m.hcutoff,
hresonance: m.hresonance,
bandf: m.bandf,
bandq: m.bandq,
duration: m.duration,
velocity: m.velocity,
delay: Delay {
wet: m.delay[0],
delay_time: m.delay[1],
feedback: m.delay[2],
},
speed: m.speed,
begin: m.begin,
end: m.end,
loop_packaged: m.loop_packaged,
};
messages_to_process.push(message_to_process);
}
async_proc_input_tx.send(messages_to_process).await.map_err(|e| e.to_string())
}
fn superdough(message: &WebAudioMessage, context: &mut AudioContext) {
let now = context.current_time();
let env = context.create_gain();
env.gain().set_value(0.);
env.connect(&context.destination());
let (lpf, hpf, bandpass) = create_filters(context, message);
match message.waveform.as_str() {
"sine" | "square" | "triangle" | "saw" => {
let osc = context.create_oscillator();
osc.set_type(create_osc_type(&message));
osc.frequency().set_value(message.note);
osc.connect(&lpf);
connect_filters_to_envelope(&env, message, &hpf, &bandpass, now);
osc.start_at(now);
osc.stop_at(now + 2.0);
}
_ => {
match File::open(format!("samples/{}/{}.wav", message.bank, message.waveform)) {
Ok(file) => {
let audio_buffer = context.decode_audio_data_sync(file).unwrap();
let audio_buffer_duration = audio_buffer.duration();
let src = context.create_buffer_source();
src.set_buffer(audio_buffer);
src.connect(&lpf);
connect_filters_to_envelope(&env, message, &hpf, &bandpass, now);
src.playback_rate().set_value(message.speed);
if message.loop_packaged.0 == 1 {
src.set_loop(true);
src.set_loop_start(message.loop_packaged.1);
src.set_loop_end(message.loop_packaged.2);
src.start_at_with_offset_and_duration(now, src.loop_start(), audio_buffer_duration / message.speed as f64);
};
// println!("{}", message.is_loop);
// src.start_at_with_offset_and_duration(now, message.begin * audio_buffer_duration, audio_buffer_duration / message.speed as f64);
src.stop_at(now + 2.0);
},
Err(e) => eprintln!("Failed to open file: {:?}", e),
}
}
}
}
fn create_osc_type(message: &WebAudioMessage) -> OscillatorType {
match message.waveform.as_str() {
"sine" => OscillatorType::Sine,
"square" => OscillatorType::Square,
"triangle" => OscillatorType::Triangle,
"saw" => OscillatorType::Sawtooth,
_ => panic!("Invalid oscillator type"),
}
}
fn create_filters(context: &mut AudioContext, message: &WebAudioMessage) -> (BiquadFilterNode, BiquadFilterNode, BiquadFilterNode) {
let lpf = context.create_biquad_filter();
lpf.set_type(Lowpass);
lpf.frequency().set_value(message.cutoff);
lpf.q().set_value(message.resonance);
let hpf = context.create_biquad_filter();
hpf.set_type(Highpass);
hpf.frequency().set_value(message.hcutoff);
hpf.q().set_value(message.hresonance);
let bandpass = context.create_biquad_filter();
bandpass.set_type(Bandpass);
lpf.connect(&hpf);
(lpf, hpf, bandpass)
}
fn connect_filters_to_envelope(envelope: &GainNode, message: &WebAudioMessage, hpf: &BiquadFilterNode, bandpass: &BiquadFilterNode, now: f64) {
if message.bandf > 0.0 {
bandpass.frequency().set_value(message.bandf);
bandpass.q().set_value(message.bandq);
hpf.connect(bandpass);
bandpass.connect(envelope);
} else {
hpf.connect(envelope);
}
envelope.gain()
.set_value_at_time(0., now)
.linear_ramp_to_value_at_time(message.velocity, now + 0.001)
.exponential_ramp_to_value_at_time(0.0001, now + message.duration * 2.0);
}
+2 -1
View File
@@ -22,6 +22,7 @@ import Loader from './Loader';
import { settingPatterns } from '../settings.mjs';
import { code2hash, hash2code } from './helpers.mjs';
import { isTauri } from '../tauri.mjs';
import {webaudioDesktopOutput} from "@strudel/desktopbridge";
const { latestCode } = settingsMap.get();
@@ -132,7 +133,7 @@ export function Repl({ embedded = false }) {
const { code, setCode, scheduler, evaluate, activateCode, isDirty, activeCode, pattern, started, stop, error } =
useStrudel({
initialCode: '// LOADING...',
defaultOutput: webaudioOutput,
defaultOutput: isTauri() ? webaudioDesktopOutput : webaudioOutput,
getTime,
beforeEval: async () => {
setPending(true);