experimental strudel audio engine support
This commit is contained in:
@ -16,6 +16,7 @@
|
|||||||
"@codemirror/lang-javascript": "^6.1.9",
|
"@codemirror/lang-javascript": "^6.1.9",
|
||||||
"@codemirror/theme-one-dark": "^6.1.2",
|
"@codemirror/theme-one-dark": "^6.1.2",
|
||||||
"@replit/codemirror-vim": "^6.0.14",
|
"@replit/codemirror-vim": "^6.0.14",
|
||||||
|
"@strudel.cycles/webaudio": "^0.8.2",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"codemirror": "^6.0.1",
|
"codemirror": "^6.0.1",
|
||||||
"postcss": "^8.4.27",
|
"postcss": "^8.4.27",
|
||||||
|
|||||||
77
src/API.ts
77
src/API.ts
@ -3,14 +3,28 @@ import { scale } from './Scales';
|
|||||||
import { tryEvaluate } from "./Evaluator";
|
import { tryEvaluate } from "./Evaluator";
|
||||||
import { MidiConnection } from "./IO/MidiConnection";
|
import { MidiConnection } from "./IO/MidiConnection";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
import { webaudioOutput, samples } from '@strudel.cycles/webaudio';
|
||||||
|
// @ts-ignore
|
||||||
import { ZZFX, zzfx } from "zzfx";
|
import { ZZFX, zzfx } from "zzfx";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const sound = (value: any) => ({
|
||||||
|
value,
|
||||||
|
context: {},
|
||||||
|
ensureObjectValue: () => { }
|
||||||
|
});
|
||||||
|
|
||||||
export class UserAPI {
|
export class UserAPI {
|
||||||
|
|
||||||
variables: { [key: string]: any } = {}
|
variables: { [key: string]: any } = {}
|
||||||
MidiConnection: MidiConnection = new MidiConnection()
|
MidiConnection: MidiConnection = new MidiConnection()
|
||||||
|
strudelSound = webaudioOutput()
|
||||||
|
load: samples
|
||||||
|
|
||||||
constructor(public app: Editor) { }
|
constructor(public app: Editor) {
|
||||||
|
this.load = samples("github:tidalcycles/Dirt-Samples/master");
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
// Utility functions
|
// Utility functions
|
||||||
@ -27,13 +41,15 @@ export class UserAPI {
|
|||||||
}
|
}
|
||||||
r = this.rate
|
r = this.rate
|
||||||
|
|
||||||
script(...args: number[]): void {
|
script(...args: number[]): void {
|
||||||
args.forEach(arg => { tryEvaluate(this.app, this.app.universes[
|
args.forEach(arg => {
|
||||||
this.app.selected_universe].locals[arg]) })
|
tryEvaluate(this.app, this.app.universes[
|
||||||
|
this.app.selected_universe].locals[arg])
|
||||||
|
})
|
||||||
}
|
}
|
||||||
s = this.script
|
s = this.script
|
||||||
|
|
||||||
clearscript(script: number): void {
|
clearscript(script: number): void {
|
||||||
this.app.universes[this.app.selected_universe].locals[script] = {
|
this.app.universes[this.app.selected_universe].locals[script] = {
|
||||||
candidate: '', committed: '', evaluations: 0
|
candidate: '', committed: '', evaluations: 0
|
||||||
}
|
}
|
||||||
@ -42,8 +58,8 @@ export class UserAPI {
|
|||||||
|
|
||||||
copyscript(from: number, to: number): void {
|
copyscript(from: number, to: number): void {
|
||||||
// Copy a script to another script
|
// Copy a script to another script
|
||||||
this.app.universes[this.app.selected_universe].locals[to] =
|
this.app.universes[this.app.selected_universe].locals[to] =
|
||||||
this.app.universes[this.app.selected_universe].locals[from]
|
this.app.universes[this.app.selected_universe].locals[from]
|
||||||
}
|
}
|
||||||
cps = this.copyscript
|
cps = this.copyscript
|
||||||
|
|
||||||
@ -55,7 +71,7 @@ export class UserAPI {
|
|||||||
public midi_outputs(): void {
|
public midi_outputs(): void {
|
||||||
console.log(this.MidiConnection.listMidiOutputs())
|
console.log(this.MidiConnection.listMidiOutputs())
|
||||||
}
|
}
|
||||||
|
|
||||||
public midi_output(outputName: string): void {
|
public midi_output(outputName: string): void {
|
||||||
if (!outputName) {
|
if (!outputName) {
|
||||||
console.log(this.MidiConnection.getCurrentMidiPort())
|
console.log(this.MidiConnection.getCurrentMidiPort())
|
||||||
@ -69,7 +85,7 @@ export class UserAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public note(note: number, channel: number, velocity: number, duration: number): void {
|
public note(note: number, channel: number, velocity: number, duration: number): void {
|
||||||
this.MidiConnection.sendMidiNote( note, channel, velocity, duration)
|
this.MidiConnection.sendMidiNote(note, channel, velocity, duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
public midi_clock(): void {
|
public midi_clock(): void {
|
||||||
@ -97,7 +113,7 @@ export class UserAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
v = this.variable
|
v = this.variable
|
||||||
|
|
||||||
public delete_variable(name: string): void {
|
public delete_variable(name: string): void {
|
||||||
delete this.variables[name]
|
delete this.variables[name]
|
||||||
}
|
}
|
||||||
@ -111,7 +127,7 @@ export class UserAPI {
|
|||||||
// =============================================================
|
// =============================================================
|
||||||
// Small algorithmic functions
|
// Small algorithmic functions
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
|
||||||
pick<T>(...array: T[]): T { return array[Math.floor(Math.random() * array.length)] }
|
pick<T>(...array: T[]): T { return array[Math.floor(Math.random() * array.length)] }
|
||||||
seqbeat<T>(...array: T[]): T { return array[this.app.clock.time_position.beat % array.length] }
|
seqbeat<T>(...array: T[]): T { return array[this.app.clock.time_position.beat % array.length] }
|
||||||
seqbar<T>(...array: T[]): T { return array[this.app.clock.time_position.bar % array.length] }
|
seqbar<T>(...array: T[]): T { return array[this.app.clock.time_position.bar % array.length] }
|
||||||
@ -130,30 +146,30 @@ export class UserAPI {
|
|||||||
// =============================================================
|
// =============================================================
|
||||||
|
|
||||||
public quantize(value: number, quantization: number[]): number {
|
public quantize(value: number, quantization: number[]): number {
|
||||||
if (quantization.length === 0) { return value }
|
if (quantization.length === 0) { return value }
|
||||||
let closest = quantization[0]
|
let closest = quantization[0]
|
||||||
quantization.forEach(q => {
|
quantization.forEach(q => {
|
||||||
if (Math.abs(q - value) < Math.abs(closest - value)) { closest = q }
|
if (Math.abs(q - value) < Math.abs(closest - value)) { closest = q }
|
||||||
})
|
})
|
||||||
return closest
|
return closest
|
||||||
}
|
}
|
||||||
quant = this.quantize
|
quant = this.quantize
|
||||||
|
|
||||||
public clamp(value: number, min: number, max: number): number {
|
public clamp(value: number, min: number, max: number): number {
|
||||||
return Math.min(Math.max(value, min), max)
|
return Math.min(Math.max(value, min), max)
|
||||||
}
|
}
|
||||||
cmp = this.clamp
|
cmp = this.clamp
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
// Transport functions
|
// Transport functions
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
|
||||||
bpm(bpm: number):void {
|
bpm(bpm: number): void {
|
||||||
this.app.clock.bpm = bpm
|
this.app.clock.bpm = bpm
|
||||||
}
|
}
|
||||||
|
|
||||||
time_signature(numerator: number, denominator: number):void {
|
time_signature(numerator: number, denominator: number): void {
|
||||||
this.app.clock.time_signature = [ numerator, denominator ]
|
this.app.clock.time_signature = [numerator, denominator]
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
@ -182,8 +198,8 @@ export class UserAPI {
|
|||||||
get e7() { return this.app.universes[this.app.selected_universe].locals[6].evaluations }
|
get e7() { return this.app.universes[this.app.selected_universe].locals[6].evaluations }
|
||||||
get e8() { return this.app.universes[this.app.selected_universe].locals[7].evaluations }
|
get e8() { return this.app.universes[this.app.selected_universe].locals[7].evaluations }
|
||||||
get e9() { return this.app.universes[this.app.selected_universe].locals[8].evaluations }
|
get e9() { return this.app.universes[this.app.selected_universe].locals[8].evaluations }
|
||||||
public evaluations_number(index:number): number {
|
public evaluations_number(index: number): number {
|
||||||
return this.app.universes[this.app.selected_universe].locals[index].evaluations
|
return this.app.universes[this.app.selected_universe].locals[index].evaluations
|
||||||
}
|
}
|
||||||
e = this.evaluations_number
|
e = this.evaluations_number
|
||||||
|
|
||||||
@ -214,14 +230,14 @@ export class UserAPI {
|
|||||||
return final_pulses.some(p => p == true)
|
return final_pulses.some(p => p == true)
|
||||||
}
|
}
|
||||||
|
|
||||||
every(...n: number[]): boolean {
|
every(...n: number[]): boolean {
|
||||||
return n.some(n => this.i % n === 0)
|
return n.some(n => this.i % n === 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
mod(...pulse: number[]): boolean { return pulse.some(p => this.app.clock.time_position.pulse % p === 0) }
|
mod(...pulse: number[]): boolean { return pulse.some(p => this.app.clock.time_position.pulse % p === 0) }
|
||||||
|
|
||||||
modbar(...bar: number[]): boolean { return bar.some(b => this.app.clock.time_position.bar % b === 0) }
|
modbar(...bar: number[]): boolean { return bar.some(b => this.app.clock.time_position.bar % b === 0) }
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
// Trivial functions
|
// Trivial functions
|
||||||
// =============================================================
|
// =============================================================
|
||||||
@ -229,4 +245,9 @@ export class UserAPI {
|
|||||||
// Small ZZFX interface for playing with this synth
|
// Small ZZFX interface for playing with this synth
|
||||||
zzfx = (...thing: number[]) => zzfx(...thing);
|
zzfx = (...thing: number[]) => zzfx(...thing);
|
||||||
|
|
||||||
|
playSound = async (values: object) => {
|
||||||
|
await this.load;
|
||||||
|
webaudioOutput(sound(values), 0.01)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
20
yarn.lock
20
yarn.lock
@ -301,6 +301,21 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@replit/codemirror-vim/-/codemirror-vim-6.0.14.tgz#8f44740b0497406b551726946c9b30f21c867671"
|
resolved "https://registry.yarnpkg.com/@replit/codemirror-vim/-/codemirror-vim-6.0.14.tgz#8f44740b0497406b551726946c9b30f21c867671"
|
||||||
integrity sha512-wwhqhvL76FdRTdwfUWpKCbv0hkp2fvivfMosDVlL/popqOiNLtUhL02ThgHZH8mus/NkVr5Mj582lyFZqQrjOA==
|
integrity sha512-wwhqhvL76FdRTdwfUWpKCbv0hkp2fvivfMosDVlL/popqOiNLtUhL02ThgHZH8mus/NkVr5Mj582lyFZqQrjOA==
|
||||||
|
|
||||||
|
"@strudel.cycles/core@0.8.2":
|
||||||
|
version "0.8.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@strudel.cycles/core/-/core-0.8.2.tgz#62e957a3636b39938d1c4ecc3fd766d02fc523bb"
|
||||||
|
integrity sha512-rmtrDfy6S/NH9HgFy4rVRRAwVXzYvR85Qwqr/WQqEZQh6OCBW9yXQQWGOZYiBi85Y2FZqwWppBImyGVA6ZzuyA==
|
||||||
|
dependencies:
|
||||||
|
fraction.js "^4.2.0"
|
||||||
|
|
||||||
|
"@strudel.cycles/webaudio@^0.8.2":
|
||||||
|
version "0.8.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@strudel.cycles/webaudio/-/webaudio-0.8.2.tgz#90e7254544d9601f4365a21f3e0dcdfbc952aded"
|
||||||
|
integrity sha512-IdjSuqd8BUYJ8BOl3lJ8uJCR4G5g0W1YryhPp3uUQ7NaVDlaM4ZnC8qejEI8yoBF+ntWKHInjf5qpj7v5+ttbA==
|
||||||
|
dependencies:
|
||||||
|
"@strudel.cycles/core" "0.8.2"
|
||||||
|
nanostores "^0.8.1"
|
||||||
|
|
||||||
any-promise@^1.0.0:
|
any-promise@^1.0.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
|
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
|
||||||
@ -651,6 +666,11 @@ nanoid@^3.3.6:
|
|||||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
|
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
|
||||||
integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
|
integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
|
||||||
|
|
||||||
|
nanostores@^0.8.1:
|
||||||
|
version "0.8.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/nanostores/-/nanostores-0.8.1.tgz#963577028ac10eeb50bec376535f4762ab5af9be"
|
||||||
|
integrity sha512-1ZCfQtII2XeFDrtqXL2cdQ/diGrLxzRB3YMyQjn8m7GSGQrJfGST2iuqMpWnS/ZlifhtjgR/SX0Jy6Uij6lRLA==
|
||||||
|
|
||||||
node-releases@^2.0.12:
|
node-releases@^2.0.12:
|
||||||
version "2.0.13"
|
version "2.0.13"
|
||||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d"
|
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d"
|
||||||
|
|||||||
Reference in New Issue
Block a user