mirror of
https://codeberg.org/uzu/strudel
synced 2026-10-19 05:24:52 -04:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a2811ba35b | |||
| 61b6e96a4a | |||
| c33c845562 | |||
| 1df7e03668 | |||
| 276979f48a | |||
| 7e719c35f2 | |||
| a2c5af1673 | |||
| 2619144353 | |||
| e8a9974518 | |||
| a458dcf9fd | |||
| 8dbf5ce74c | |||
| 7f02baf93b | |||
| 2cf3ffa507 | |||
| 3583091e43 | |||
| 0ecf60f751 | |||
| 73c57f0f9d | |||
| cc8c9f1c26 | |||
| bcec4695a0 | |||
| e782debc15 | |||
| 459768af2a | |||
| 173a1654c8 | |||
| dedd687a1f | |||
| 6abb9f85a8 | |||
| 4f3ba01afc | |||
| f440d7869c | |||
| 13d404613c | |||
| f54a1f07d2 | |||
| 44e371c99d | |||
| c8d0342ecb | |||
| 096e53690f | |||
| d385ceba39 | |||
| e3e3cdfcfc |
@@ -0,0 +1,41 @@
|
||||
# Code of Conduct
|
||||
|
||||
## The Short Version
|
||||
|
||||
We are dedicated to providing a harassment-free experience for everyone, regardless of gender, gender identity and expression, age, sexual orientation, disability, physical appearance, body size, race, ethnicity, religion (or lack thereof), technology choices, and so on. This applies both in person or via online media.
|
||||
|
||||
## The Less Short Version
|
||||
|
||||
Harassment includes offensive verbal comments related to gender, gender identity and expression, age, sexual orientation, disability, physical appearance, body size, race, ethnicity, religion, technology choices, deliberate intimidation, stalking, following, disruption of performances, inappropriate physical contact, and unwelcome sexual attention.
|
||||
|
||||
If you are being harassed, notice that someone else is being harassed, or have any other concerns, please contact an admin immediately.
|
||||
|
||||
If you report an incident of harassment you can expect to be listened to and taken seriously. The admin will take action they deem appropriate in response depending on the scale and severity of the incident. For example:
|
||||
|
||||
1. Discuss the perpetrator’s behaviour with them and ask them to stop. Explain what they have done and why it is unacceptable. Remind the perpetrator of the code of conduct. Monitor the perpetrator’s behaviour and if it improves then they will continue to be welcome.
|
||||
2. Temporarily exclude the perpetrator from the forum for a cool-off period. Explain what they have done and why it is unacceptable and remind them of the code of conduct. Monitor the person’s behaviour and if it improves then they will continue to be welcome.
|
||||
3. Remove the perpetrator from the forum. Explain what they have done and why it is unacceptable and remind them of the code of conduct.
|
||||
|
||||
# Post-AI humane policy for live coding development
|
||||
|
||||
Please follow the following policy on AI/LLM use.
|
||||
|
||||
## Community
|
||||
|
||||
All community members should be treated with respect and kindness. We welcome contributors to the community who are ready to follow this policy as well as the above code of conduct.
|
||||
|
||||
## Principles
|
||||
|
||||
* We wish to protect the humanity of our communities and projects, to support the motivation and mental health of all of its contributors and users.
|
||||
* To this end, contributors and other users of our projects should not have to engage with LLM-generated code and text as part of their community work.
|
||||
* We recognise that LLM-based scraping and generation of (A)GPL code shared by ourselves and others is of questionable legality. For example under many juristictions, LLM-generated work does not have a copyright holder and can therefore not be licensed under the (A)GPL.
|
||||
* A contributor's personal use of LLMs and related technology is their own business, whether for research, analysis, bug discovery or other assistive technology, so long as the output is not included in any contributions to our projects.
|
||||
|
||||
## In practice
|
||||
|
||||
* Contributions including LLM-generated content will be declined.
|
||||
* LLM-generated text (e.g. commit messages, issue comments, forum posts etc) generated by LLMs will be flagged, and ultimately deleted.
|
||||
* We encourage asking each other questions and working through problems to promote collective knowledge and creative ideas (never telling each other to "just google it").
|
||||
* We strongly discourage others from forking/importing our projects into corporate AI platforms, including Microsoft Github.
|
||||
* All contributions must be submitted by a human who understands the changes, is happy to answer questions about them, and where possible, help maintain the code in the future.
|
||||
* Where stipulated, discussion (including criticism) of LLM technology and use should be kept to designated channels.
|
||||
@@ -42,7 +42,6 @@ export default [
|
||||
'**/hydra.mjs',
|
||||
'**/jsdoc-synonyms.js',
|
||||
'packages/hs2js/src/hs2js.mjs',
|
||||
'packages/supradough/dough-export.mjs',
|
||||
'**/samples',
|
||||
],
|
||||
},
|
||||
|
||||
+52
-66
@@ -446,7 +446,7 @@ export const { accelerate } = registerControl('accelerate');
|
||||
* Sets the velocity from 0 to 1. Is multiplied together with gain.
|
||||
*
|
||||
* @name velocity
|
||||
* @tags amplitude, superdough, supradough
|
||||
* @tags amplitude, superdough
|
||||
* @synonyms vel
|
||||
* @example
|
||||
* s("hh*8")
|
||||
@@ -458,7 +458,7 @@ export const { velocity, vel } = registerControl('velocity', 'vel');
|
||||
* Controls the gain by an exponential amount.
|
||||
*
|
||||
* @name gain
|
||||
* @tags amplitude, superdough, supradough
|
||||
* @tags amplitude, superdough
|
||||
* @param {number | Pattern} amount gain.
|
||||
* @example
|
||||
* s("hh*8").gain(".4!2 1 .4!2 1 .4 1").fast(2)
|
||||
@@ -469,7 +469,7 @@ export const { gain } = registerControl('gain');
|
||||
* Gain applied after all effects have been processed.
|
||||
*
|
||||
* @name postgain
|
||||
* @tags amplitude, superdough, supradough
|
||||
* @tags amplitude, superdough
|
||||
* @example
|
||||
* s("bd sd [~ bd] sd,hh*8")
|
||||
* .compressor("-20:20:10:.002:.02").postgain(1.5)
|
||||
@@ -499,7 +499,7 @@ export const { amp } = registerControl('amp');
|
||||
* any of the 8 individual FMs (e.g. `fmh2`)
|
||||
*
|
||||
* @name fmh
|
||||
* @tags fm, superdough, supradough
|
||||
* @tags fm, superdough
|
||||
* @param {number | Pattern} harmonicity
|
||||
* @example
|
||||
* note("c e g b g e")
|
||||
@@ -520,7 +520,7 @@ export const { fmh, fmh1, fmh2, fmh3, fmh4, fmh5, fmh6, fmh7, fmh8 } = registerM
|
||||
* `fm3`
|
||||
*
|
||||
* @name fm
|
||||
* @tags fm, superdough, supradough
|
||||
* @tags fm, superdough
|
||||
* @param {number | Pattern} brightness modulation index
|
||||
* @synonyms fmi
|
||||
* @example
|
||||
@@ -544,7 +544,7 @@ export const { fmi, fmi1, fmi2, fmi3, fmi4, fmi5, fmi6, fmi7, fmi8, fm, fm1, fm2
|
||||
* any of the 8 individual FMs (e.g. `fmenv4`)
|
||||
*
|
||||
* @name fmenv
|
||||
* @tags fm, envelope, superdough, supradough
|
||||
* @tags fm, envelope, superdough
|
||||
* @param {number | Pattern} type lin | exp
|
||||
* @synonyms fme
|
||||
* @example
|
||||
@@ -569,7 +569,7 @@ export const { fmenv, fmenv1, fmenv2, fmenv3, fmenv4, fmenv5, fmenv6, fmenv7, fm
|
||||
* any of the 8 individual FMs (e.g. `fmatt5`)
|
||||
*
|
||||
* @name fmattack
|
||||
* @tags fm, envelope, superdough, supradough
|
||||
* @tags fm, envelope, superdough
|
||||
* @synonyms fmatt
|
||||
* @param {number | Pattern} time attack time
|
||||
* @synonyms fmatt
|
||||
@@ -608,7 +608,7 @@ export const {
|
||||
* any of the 8 individual FMs (e.g. `fmwave6`)
|
||||
*
|
||||
* @name fmwave
|
||||
* @tags fm, superdough, supradough
|
||||
* @tags fm, superdough
|
||||
* @param {number | Pattern} wave waveform
|
||||
* @example
|
||||
* n("0 1 2 3".fast(4)).scale("d:minor").s("sine").fmwave("<sine square sawtooth crackle>").fm(4).fmh(2.01)
|
||||
@@ -628,7 +628,7 @@ export const { fmwave, fmwave1, fmwave2, fmwave3, fmwave4, fmwave5, fmwave6, fmw
|
||||
* any of the 8 individual FMs (e.g. `fmdec6`)
|
||||
*
|
||||
* @name fmdecay
|
||||
* @tags fm, envelope, superdough, supradough
|
||||
* @tags fm, envelope, superdough
|
||||
* @synonyms fmdec
|
||||
* @param {number | Pattern} time decay time
|
||||
* @synonyms fmdec
|
||||
@@ -668,7 +668,7 @@ export const {
|
||||
* any of the 8 individual FMs (e.g. `fmsus7`)
|
||||
*
|
||||
* @name fmsustain
|
||||
* @tags fm, envelope, superdough, supradough
|
||||
* @tags fm, envelope, superdough
|
||||
* @synonyms fmsus
|
||||
* @param {number | Pattern} level sustain level
|
||||
* @synonyms fmsus
|
||||
@@ -708,7 +708,7 @@ export const {
|
||||
* any of the 8 individual FMs (e.g. `fmrel8`)
|
||||
*
|
||||
* @name fmrelease
|
||||
* @tags fm, envelope, superdough, supradough
|
||||
* @tags fm, envelope, superdough
|
||||
* @synonyms fmrel
|
||||
* @param {number | Pattern} time release time
|
||||
*
|
||||
@@ -778,7 +778,7 @@ export const { fft } = registerControl('fft');
|
||||
* Amplitude envelope attack time: Specifies how long it takes for the sound to reach its peak value, relative to the onset.
|
||||
*
|
||||
* @name attack
|
||||
* @tags amplitude, envelope, superdough, supradough
|
||||
* @tags amplitude, envelope, superdough
|
||||
* @param {number | Pattern} attack time in seconds.
|
||||
* @synonyms att
|
||||
* @example
|
||||
@@ -792,7 +792,7 @@ export const { attack, att } = registerControl('attack', 'att');
|
||||
* Note that the decay is only audible if the sustain value is lower than 1.
|
||||
*
|
||||
* @name decay
|
||||
* @tags amplitude, envelope, superdough, supradough
|
||||
* @tags amplitude, envelope, superdough
|
||||
* @param {number | Pattern} time decay time in seconds
|
||||
* @synonyms dec
|
||||
* @example
|
||||
@@ -804,7 +804,7 @@ export const { decay, dec } = registerControl('decay', 'dec');
|
||||
* Amplitude envelope sustain level: The level which is reached after attack / decay, being sustained until the offset.
|
||||
*
|
||||
* @name sustain
|
||||
* @tags amplitude, envelope, superdough, supradough
|
||||
* @tags amplitude, envelope, superdough
|
||||
* @param {number | Pattern} gain sustain level between 0 and 1
|
||||
* @synonyms sus
|
||||
* @example
|
||||
@@ -816,7 +816,7 @@ export const { sustain, sus } = registerControl('sustain', 'sus');
|
||||
* Amplitude envelope release time: The time it takes after the offset to go from sustain level to zero.
|
||||
*
|
||||
* @name release
|
||||
* @tags amplitude, envelope, superdough, supradough
|
||||
* @tags amplitude, envelope, superdough
|
||||
* @param {number | Pattern} time release time in seconds
|
||||
* @synonyms rel
|
||||
* @example
|
||||
@@ -831,7 +831,7 @@ export const { hold } = registerControl('hold');
|
||||
* can also optionally supply the 'bpq' parameter separated by ':'.
|
||||
*
|
||||
* @name bpf
|
||||
* @tags filter, superdough, supradough
|
||||
* @tags filter, superdough
|
||||
* @param {number | Pattern} frequency center frequency
|
||||
* @synonyms bandf, bp
|
||||
* @example
|
||||
@@ -844,7 +844,7 @@ export const { bandf, bpf, bp } = registerControl(['bandf', 'bandq', 'bpenv'], '
|
||||
* Sets the **b**and-**p**ass **q**-factor (resonance).
|
||||
*
|
||||
* @name bpq
|
||||
* @tags filter, superdough, supradough
|
||||
* @tags filter, superdough
|
||||
* @param {number | Pattern} q q factor
|
||||
* @synonyms bandq
|
||||
* @example
|
||||
@@ -923,7 +923,7 @@ export const { loopEnd, loope } = registerControl('loopEnd', 'loope');
|
||||
* Bit crusher effect.
|
||||
*
|
||||
* @name crush
|
||||
* @tags superdough, supradough
|
||||
* @tags superdough
|
||||
* @param {number | Pattern} depth between 1 (for drastic reduction in bit-depth) to 16 (for barely no reduction).
|
||||
* @example
|
||||
* s("<bd sd>,hh*3").fast(2).crush("<16 8 7 6 5 4 3 2>")
|
||||
@@ -935,7 +935,7 @@ export const { crush } = registerControl('crush');
|
||||
* Fake-resampling for lowering the sample rate. Caution: This effect seems to only work in chromium based browsers
|
||||
*
|
||||
* @name coarse
|
||||
* @tags superdough, supradough
|
||||
* @tags superdough
|
||||
* @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on.
|
||||
* @example
|
||||
* s("bd sd [~ bd] sd,hh*8").coarse("<1 4 8 16 32>")
|
||||
@@ -1294,7 +1294,7 @@ export const { cut } = registerControl('cut');
|
||||
* When using mininotation, you can also optionally add the 'lpq' parameter, separated by ':'.
|
||||
*
|
||||
* @name lpf
|
||||
* @tags filter, superdough, supradough
|
||||
* @tags filter, superdough
|
||||
* @param {number | Pattern} frequency audible between 0 and 20000
|
||||
* @synonyms cutoff, ctf, lp
|
||||
* @example
|
||||
@@ -1308,7 +1308,7 @@ export const { cutoff, ctf, lpf, lp } = registerControl(['cutoff', 'resonance',
|
||||
/**
|
||||
* Sets the lowpass filter envelope modulation depth.
|
||||
* @name lpenv
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_
|
||||
* @synonyms lpe
|
||||
* @example
|
||||
@@ -1322,7 +1322,7 @@ export const { lpenv, lpe } = registerControl('lpenv', 'lpe');
|
||||
/**
|
||||
* Sets the highpass filter envelope modulation depth.
|
||||
* @name hpenv
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_
|
||||
* @synonyms hpe
|
||||
* @example
|
||||
@@ -1336,7 +1336,7 @@ export const { hpenv, hpe } = registerControl('hpenv', 'hpe');
|
||||
/**
|
||||
* Sets the bandpass filter envelope modulation depth.
|
||||
* @name bpenv
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_
|
||||
* @synonyms bpe
|
||||
* @example
|
||||
@@ -1350,7 +1350,7 @@ export const { bpenv, bpe } = registerControl('bpenv', 'bpe');
|
||||
/**
|
||||
* Sets the attack duration for the lowpass filter envelope.
|
||||
* @name lpattack
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} attack time of the filter envelope
|
||||
* @synonyms lpa
|
||||
* @example
|
||||
@@ -1364,7 +1364,7 @@ export const { lpattack, lpa } = registerControl('lpattack', 'lpa');
|
||||
/**
|
||||
* Sets the attack duration for the highpass filter envelope.
|
||||
* @name hpattack
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} attack time of the highpass filter envelope
|
||||
* @synonyms hpa
|
||||
* @example
|
||||
@@ -1378,7 +1378,7 @@ export const { hpattack, hpa } = registerControl('hpattack', 'hpa');
|
||||
/**
|
||||
* Sets the attack duration for the bandpass filter envelope.
|
||||
* @name bpattack
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} attack time of the bandpass filter envelope
|
||||
* @synonyms bpa
|
||||
* @example
|
||||
@@ -1392,7 +1392,7 @@ export const { bpattack, bpa } = registerControl('bpattack', 'bpa');
|
||||
/**
|
||||
* Sets the decay duration for the lowpass filter envelope.
|
||||
* @name lpdecay
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} decay time of the filter envelope
|
||||
* @synonyms lpd
|
||||
* @example
|
||||
@@ -1406,7 +1406,7 @@ export const { lpdecay, lpd } = registerControl('lpdecay', 'lpd');
|
||||
/**
|
||||
* Sets the decay duration for the highpass filter envelope.
|
||||
* @name hpdecay
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} decay time of the highpass filter envelope
|
||||
* @synonyms hpd
|
||||
* @example
|
||||
@@ -1421,7 +1421,7 @@ export const { hpdecay, hpd } = registerControl('hpdecay', 'hpd');
|
||||
/**
|
||||
* Sets the decay duration for the bandpass filter envelope.
|
||||
* @name bpdecay
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} decay time of the bandpass filter envelope
|
||||
* @synonyms bpd
|
||||
* @example
|
||||
@@ -1436,7 +1436,7 @@ export const { bpdecay, bpd } = registerControl('bpdecay', 'bpd');
|
||||
/**
|
||||
* Sets the sustain amplitude for the lowpass filter envelope.
|
||||
* @name lpsustain
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} sustain amplitude of the lowpass filter envelope
|
||||
* @synonyms lps
|
||||
* @example
|
||||
@@ -1451,7 +1451,7 @@ export const { lpsustain, lps } = registerControl('lpsustain', 'lps');
|
||||
/**
|
||||
* Sets the sustain amplitude for the highpass filter envelope.
|
||||
* @name hpsustain
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} sustain amplitude of the highpass filter envelope
|
||||
* @synonyms hps
|
||||
* @example
|
||||
@@ -1466,7 +1466,7 @@ export const { hpsustain, hps } = registerControl('hpsustain', 'hps');
|
||||
/**
|
||||
* Sets the sustain amplitude for the bandpass filter envelope.
|
||||
* @name bpsustain
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} sustain amplitude of the bandpass filter envelope
|
||||
* @synonyms bps
|
||||
* @example
|
||||
@@ -1481,7 +1481,7 @@ export const { bpsustain, bps } = registerControl('bpsustain', 'bps');
|
||||
/**
|
||||
* Sets the release time for the lowpass filter envelope.
|
||||
* @name lprelease
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} release time of the filter envelope
|
||||
* @synonyms lpr
|
||||
* @example
|
||||
@@ -1497,7 +1497,7 @@ export const { lprelease, lpr } = registerControl('lprelease', 'lpr');
|
||||
/**
|
||||
* Sets the release time for the highpass filter envelope.
|
||||
* @name hprelease
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} release time of the highpass filter envelope
|
||||
* @synonyms hpr
|
||||
* @example
|
||||
@@ -1513,7 +1513,7 @@ export const { hprelease, hpr } = registerControl('hprelease', 'hpr');
|
||||
/**
|
||||
* Sets the release time for the bandpass filter envelope.
|
||||
* @name bprelease
|
||||
* @tags filter, envelope, superdough, supradough
|
||||
* @tags filter, envelope, superdough
|
||||
* @param {number | Pattern} release time of the bandpass filter envelope
|
||||
* @synonyms bpr
|
||||
* @example
|
||||
@@ -1558,7 +1558,7 @@ export const { fanchor } = registerControl('fanchor');
|
||||
* When using mininotation, you can also optionally add the 'hpq' parameter, separated by ':'.
|
||||
*
|
||||
* @name hpf
|
||||
* @tags filter, superdough, supradough
|
||||
* @tags filter, superdough
|
||||
* @param {number | Pattern} frequency audible between 0 and 20000
|
||||
* @synonyms hp, hcutoff
|
||||
* @example
|
||||
@@ -1781,7 +1781,7 @@ export const { hpskew } = registerControl('hpskew');
|
||||
* Applies a vibrato to the frequency of the oscillator.
|
||||
*
|
||||
* @name vib
|
||||
* @tags pitch, lfo, superdough, supradough
|
||||
* @tags pitch, lfo, superdough
|
||||
* @synonyms vibrato, v
|
||||
* @param {number | Pattern} frequency of the vibrato in hertz
|
||||
* @example
|
||||
@@ -1799,7 +1799,7 @@ export const { vib, vibrato, v } = registerControl(['vib', 'vibmod'], 'vibrato',
|
||||
* Adds pink noise to the mix
|
||||
*
|
||||
* @name noise
|
||||
* @tags generators, superdough, supradough
|
||||
* @tags generators, superdough
|
||||
* @param {number | Pattern} wet wet amount
|
||||
* @example
|
||||
* sound("<white pink brown>/2")
|
||||
@@ -1809,7 +1809,7 @@ export const { noise } = registerControl('noise');
|
||||
* Sets the vibrato depth in semitones. Only has an effect if `vibrato` | `vib` | `v` is is also set
|
||||
*
|
||||
* @name vibmod
|
||||
* @tags pitch, lfo, superdough, supradough
|
||||
* @tags pitch, lfo, superdough
|
||||
* @synonyms vmod
|
||||
* @param {number | Pattern} depth of vibrato (in semitones)
|
||||
* @example
|
||||
@@ -1828,7 +1828,7 @@ export const { hcutoff, hpf, hp } = registerControl(['hcutoff', 'hresonance', 'h
|
||||
* Controls the **h**igh-**p**ass **q**-value.
|
||||
*
|
||||
* @name hpq
|
||||
* @tags filter, superdough, supradough
|
||||
* @tags filter, superdough
|
||||
* @param {number | Pattern} q resonance factor between 0 and 50
|
||||
* @synonyms hresonance
|
||||
* @example
|
||||
@@ -1840,7 +1840,7 @@ export const { hresonance, hpq } = registerControl('hresonance', 'hpq');
|
||||
* Controls the **l**ow-**p**ass **q**-value.
|
||||
*
|
||||
* @name lpq
|
||||
* @tags filter, superdough, supradough
|
||||
* @tags filter, superdough
|
||||
* @param {number | Pattern} q resonance factor between 0 and 50
|
||||
* @synonyms resonance
|
||||
* @example
|
||||
@@ -1870,7 +1870,7 @@ export const { djf } = registerControl('djf');
|
||||
*
|
||||
*
|
||||
* @name delay
|
||||
* @tags orbit, superdough, supradough
|
||||
* @tags orbit, superdough
|
||||
* @param {number | Pattern} level between 0 and 1
|
||||
* @example
|
||||
* s("bd bd").delay("<0 .25 .5 1>")
|
||||
@@ -1884,7 +1884,7 @@ export const { delay } = registerControl(['delay', 'delaytime', 'delayfeedback']
|
||||
* Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it
|
||||
*
|
||||
* @name delayfeedback
|
||||
* @tags orbit, superdough, supradough
|
||||
* @tags orbit, superdough
|
||||
* @param {number | Pattern} feedback between 0 and 1
|
||||
* @synonyms delayfb, dfb
|
||||
* @example
|
||||
@@ -1893,24 +1893,11 @@ export const { delay } = registerControl(['delay', 'delaytime', 'delayfeedback']
|
||||
*/
|
||||
export const { delayfeedback, delayfb, dfb } = registerControl('delayfeedback', 'delayfb', 'dfb');
|
||||
|
||||
/**
|
||||
* Sets the time of the delay effect.
|
||||
*
|
||||
* @name delayspeed
|
||||
* @tags supradough
|
||||
* @param {number | Pattern} delayspeed controls the pitch of the delay feedback
|
||||
* @synonyms delayt, dt
|
||||
* @example
|
||||
* note("d d a# a".fast(2)).s("sawtooth").delay(.8).delaytime(1/2).delayspeed("<2 .5 -1 -2>")
|
||||
*
|
||||
*/
|
||||
export const { delayspeed } = registerControl('delayspeed');
|
||||
|
||||
/**
|
||||
* Sets the time of the delay effect in seconds.
|
||||
*
|
||||
* @name delaytime
|
||||
* @tags orbit, superdough, supradough
|
||||
* @tags orbit, superdough
|
||||
* @param {number | Pattern} delay in seconds
|
||||
* @synonyms delayt, dt
|
||||
* @example
|
||||
@@ -1918,7 +1905,6 @@ export const { delayspeed } = registerControl('delayspeed');
|
||||
* .s("sawtooth")
|
||||
* .delay(.8)
|
||||
* .delaytime(1/2)
|
||||
* .delayspeed("<2 .5 -1 -2>")
|
||||
*/
|
||||
export const { delaytime, delayt, dt } = registerControl('delaytime', 'delayt', 'dt');
|
||||
|
||||
@@ -2026,7 +2012,7 @@ export const { freq } = registerControl('freq');
|
||||
* Attack time of pitch envelope.
|
||||
*
|
||||
* @name pattack
|
||||
* @tags pitch, envelope, superdough, supradough
|
||||
* @tags pitch, envelope, superdough
|
||||
* @synonyms patt
|
||||
* @param {number | Pattern} time time in seconds
|
||||
* @example
|
||||
@@ -2038,7 +2024,7 @@ export const { pattack, patt } = registerControl('pattack', 'patt');
|
||||
* Decay time of pitch envelope.
|
||||
*
|
||||
* @name pdecay
|
||||
* @tags pitch, envelope, superdough, supradough
|
||||
* @tags pitch, envelope, superdough
|
||||
* @synonyms pdec
|
||||
* @param {number | Pattern} time time in seconds
|
||||
* @example
|
||||
@@ -2052,7 +2038,7 @@ export const { psustain, psus } = registerControl('psustain', 'psus');
|
||||
* Release time of pitch envelope
|
||||
*
|
||||
* @name prelease
|
||||
* @tags pitch, envelope, superdough, supradough
|
||||
* @tags pitch, envelope, superdough
|
||||
* @synonyms prel
|
||||
* @param {number | Pattern} time time in seconds
|
||||
* @example
|
||||
@@ -2067,7 +2053,7 @@ export const { prelease, prel } = registerControl('prelease', 'prel');
|
||||
* If you don't set other pitch envelope controls, `pattack:.2` will be the default.
|
||||
*
|
||||
* @name penv
|
||||
* @tags pitch, envelope, superdough, supradough
|
||||
* @tags pitch, envelope, superdough
|
||||
* @param {number | Pattern} semitones change in semitones
|
||||
* @example
|
||||
* note("c")
|
||||
@@ -2248,7 +2234,7 @@ export const { overshape } = registerControl('overshape');
|
||||
* Sets position in stereo.
|
||||
*
|
||||
* @name pan
|
||||
* @tags superdough, supradough
|
||||
* @tags superdough
|
||||
* @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel)
|
||||
* @example
|
||||
* s("[bd hh]*2").pan("<.5 1 .5 0>")
|
||||
@@ -2506,7 +2492,7 @@ export const { shape } = registerControl(['shape', 'shapevol']);
|
||||
* Most useful values are usually between 0 and 10 (depending on source gain). If you are feeling adventurous, you can turn it up to 11 and beyond ;)
|
||||
*
|
||||
* @name distort
|
||||
* @tags distortion, superdough, supradough
|
||||
* @tags distortion, superdough
|
||||
* @synonyms dist
|
||||
* @param {number | Pattern} distortion amount of distortion to apply
|
||||
* @param {number | Pattern} volume linear postgain of the distortion
|
||||
@@ -2526,7 +2512,7 @@ export const { distort, dist } = registerControl(['distort', 'distortvol', 'dist
|
||||
*
|
||||
* @name distortvol
|
||||
* @synonyms distortion, distvol
|
||||
* @tags superdough, supradough
|
||||
* @tags superdough
|
||||
* @param {number | Pattern} volume linear postgain of the distortion
|
||||
* @example
|
||||
* s("bd*4").bank("tr909").distort(2).distortvol(0.8)
|
||||
@@ -2537,7 +2523,7 @@ export const { distortvol } = registerControl('distortvol', 'distvol');
|
||||
* Type of waveshaping distortion to apply.
|
||||
*
|
||||
* @name distorttype
|
||||
* @tags distortion, superdough, supradough
|
||||
* @tags distortion, superdough
|
||||
* @synonyms disttype
|
||||
* @param {number | string | Pattern} type type of distortion to apply
|
||||
* @example
|
||||
|
||||
+88
-23
@@ -28,31 +28,34 @@ export class Cyclist {
|
||||
this.started = false;
|
||||
this.beforeStart = beforeStart;
|
||||
this.cps = 0.5;
|
||||
this.num_ticks_since_cps_change = 0;
|
||||
this.checkpoint = {
|
||||
// new checkpoints are created when there's a change in cps
|
||||
cycles: 0, // number of cycles when cps was changed
|
||||
seconds: 0, // clock phase when cps was changed
|
||||
};
|
||||
this.num_ticks_since_checkpoint = 0;
|
||||
this.lastTick = 0; // absolute time when last tick (clock callback) happened
|
||||
this.lastBegin = 0; // query begin of last tick
|
||||
this.lastEnd = 0; // query end of last tick
|
||||
this.getTime = getTime; // get absolute time
|
||||
this.num_cycles_at_cps_change = 0;
|
||||
this.seconds_at_cps_change; // clock phase when cps was changed
|
||||
this.onToggle = onToggle;
|
||||
this.latency = latency; // fixed trigger time offset
|
||||
this.clock = createClock(
|
||||
getTime,
|
||||
// called slightly before each cycle
|
||||
(phase, duration, _, t) => {
|
||||
if (this.num_ticks_since_cps_change === 0) {
|
||||
this.num_cycles_at_cps_change = this.lastEnd;
|
||||
this.seconds_at_cps_change = phase;
|
||||
if (this.num_ticks_since_checkpoint === 0) {
|
||||
this.checkpoint = {
|
||||
cycles: this.lastEnd,
|
||||
seconds: phase,
|
||||
};
|
||||
}
|
||||
this.num_ticks_since_cps_change++;
|
||||
const seconds_since_cps_change = this.num_ticks_since_cps_change * duration;
|
||||
const num_cycles_since_cps_change = seconds_since_cps_change * this.cps;
|
||||
this.num_ticks_since_checkpoint++;
|
||||
|
||||
try {
|
||||
const begin = this.lastEnd;
|
||||
var begin = this.lastEnd;
|
||||
this.lastBegin = begin;
|
||||
const end = this.num_cycles_at_cps_change + num_cycles_since_cps_change;
|
||||
var end = this.checkpoint.cycles + this.num_ticks_since_checkpoint * duration * this.cps;
|
||||
this.lastEnd = end;
|
||||
this.lastTick = phase;
|
||||
|
||||
@@ -62,20 +65,79 @@ export class Cyclist {
|
||||
return;
|
||||
}
|
||||
|
||||
// query the pattern for events
|
||||
const haps = this.pattern.queryArc(begin, end, { _cps: this.cps, cyclist: 'cyclist' });
|
||||
const tickEndTime = phase + duration;
|
||||
|
||||
haps.forEach((hap) => {
|
||||
if (hap.hasOnset()) {
|
||||
const targetTime =
|
||||
(hap.whole.begin - this.num_cycles_at_cps_change) / this.cps + this.seconds_at_cps_change + latency;
|
||||
onSchedule?.(hap, targetTime, this.cps);
|
||||
var cpsChanged = false;
|
||||
do {
|
||||
cpsChanged = false;
|
||||
|
||||
// query the pattern for events
|
||||
const haps = this.pattern
|
||||
.queryArc(begin, end, { _cps: this.cps, cyclist: 'cyclist' })
|
||||
.filter((hap) => hap.hasOnset())
|
||||
// Sort the haps based on their onset, so cps changes within the
|
||||
// tick duration happen in the correct order.
|
||||
.sort((a, b) => {
|
||||
const aBegin = a.whole.begin;
|
||||
const bBegin = b.whole.begin;
|
||||
// If haps happen at the same time, trigger the haps that cause
|
||||
// cps changes first, so the durations of the simultaneous haps
|
||||
// are adjusted accordingly.
|
||||
if (aBegin.eq(bBegin)) {
|
||||
if (a.value.cps !== undefined) {
|
||||
return b.value.cps !== undefined ? 0 : -1;
|
||||
}
|
||||
if (b.value.cps !== undefined) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return aBegin.sub(bBegin);
|
||||
});
|
||||
|
||||
haps.forEach((hap) => {
|
||||
const targetTime = (hap.whole.begin - this.checkpoint.cycles) / this.cps + this.checkpoint.seconds;
|
||||
if (tickEndTime < targetTime) {
|
||||
// If the targetTime exceeds the tickEndTime, this means
|
||||
// the cps has slowed down, and the latter haps from the query
|
||||
// no longer fall within the window of the current tick.
|
||||
// They'll be scheduled during the next tick.
|
||||
return;
|
||||
}
|
||||
onSchedule?.(hap, targetTime + this.latency, hap.value.cps ?? this.cps);
|
||||
if (hap.value.cps !== undefined && this.cps != hap.value.cps) {
|
||||
cpsChanged = true;
|
||||
this.cps = hap.value.cps;
|
||||
this.num_ticks_since_cps_change = 0;
|
||||
this.num_ticks_since_checkpoint = 0;
|
||||
this.checkpoint = {
|
||||
cycles: hap.whole.begin,
|
||||
seconds: targetTime,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// If there are any haps in the query that trigger changes to the
|
||||
// cps that result in the pattern speeding up, the current cycle end
|
||||
// may not capture all the haps that need to be scheduled.
|
||||
// If this is the case, we repeat the query + scheduling with a
|
||||
// newly calculated end time.
|
||||
// This process can repeat multiple times until no additional
|
||||
// changes to the cps are triggered.
|
||||
// In practice, this doesn't happen more than once during a tick.
|
||||
if (cpsChanged) {
|
||||
begin = end;
|
||||
const remainingSecondsSinceCheckpoint = tickEndTime - this.checkpoint.seconds;
|
||||
const remainingCycles = remainingSecondsSinceCheckpoint * this.cps;
|
||||
end = this.checkpoint.cycles + remainingCycles;
|
||||
this.lastEnd = end;
|
||||
if (end < begin) {
|
||||
// If the new end is before the old end this means the track
|
||||
// slowed down, so we don't need to schedule additional haps.
|
||||
// Otherwise, schedule the remaining events.
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
} while (cpsChanged);
|
||||
} catch (e) {
|
||||
errorLogger(e);
|
||||
onError?.(e);
|
||||
@@ -101,8 +163,11 @@ export class Cyclist {
|
||||
}
|
||||
async start() {
|
||||
await this.beforeStart?.();
|
||||
this.num_ticks_since_cps_change = 0;
|
||||
this.num_cycles_at_cps_change = 0;
|
||||
this.checkpoint = {
|
||||
cycles: 0,
|
||||
seconds: 0,
|
||||
};
|
||||
this.num_ticks_since_checkpoint = 0;
|
||||
if (!this.pattern) {
|
||||
throw new Error('Scheduler: no pattern set! call .setPattern first.');
|
||||
}
|
||||
@@ -132,7 +197,7 @@ export class Cyclist {
|
||||
return;
|
||||
}
|
||||
this.cps = cps;
|
||||
this.num_ticks_since_cps_change = 0;
|
||||
this.num_ticks_since_checkpoint = 0;
|
||||
}
|
||||
log(begin, end, haps) {
|
||||
const onsets = haps.filter((h) => h.hasOnset());
|
||||
|
||||
@@ -420,7 +420,7 @@ export const binaryNL = (n, nBits = 16) => {
|
||||
* .partials(randL(8))
|
||||
*/
|
||||
export const randL = (n) => {
|
||||
return signal((t) => (nVal) => getRandsAtTime(t, nVal).map(Math.abs)).appLeft(reify(n));
|
||||
return signal((t, controls) => (nVal) => getRandsAtTime(t, nVal, controls.randSeed).map(Math.abs)).appLeft(reify(n));
|
||||
};
|
||||
|
||||
export const randrun = (n) => {
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
},
|
||||
"homepage": "https://codeberg.org/uzu/strudel/",
|
||||
"dependencies": {
|
||||
"web-tree-sitter": "^0.24.7"
|
||||
"web-tree-sitter": "^0.24.7",
|
||||
"tree-sitter-haskell": "^0.23.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tree-sitter-haskell": "^0.23.1",
|
||||
"vite": "^6.0.11"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import Parser from 'web-tree-sitter';
|
||||
import treeSitterWasm from 'web-tree-sitter/tree-sitter.wasm?url';
|
||||
import grammarWasm from 'tree-sitter-haskell/tree-sitter-haskell.wasm?url';
|
||||
|
||||
let base = '/';
|
||||
let base;
|
||||
export function setBase(path) {
|
||||
base = path;
|
||||
}
|
||||
@@ -10,11 +12,15 @@ let isReady = false,
|
||||
async function _loadParser() {
|
||||
await Parser.init({
|
||||
locateFile(scriptName, scriptDirectory) {
|
||||
return `${base}${scriptName}`;
|
||||
if (base) {
|
||||
return `${base}${scriptName}`;
|
||||
}
|
||||
return treeSitterWasm;
|
||||
},
|
||||
});
|
||||
parser = new Parser();
|
||||
const Lang = await Parser.Language.load(`${base}tree-sitter-haskell.wasm`);
|
||||
let grammarUrl = base ? `${base}tree-sitter-haskell.wasm` : grammarWasm;
|
||||
const Lang = await Parser.Language.load(grammarUrl);
|
||||
parser.setLanguage(Lang);
|
||||
isReady = true;
|
||||
return parser;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
pattern.wav
|
||||
@@ -1,3 +0,0 @@
|
||||
# supradough
|
||||
|
||||
platform agnostic synth and sampler intended for live coding. a reimplementation of superdough.
|
||||
@@ -1,123 +0,0 @@
|
||||
// this is a poc of how a pattern can be rendered as a wav file using node
|
||||
// run via: node dough-export.mjs
|
||||
import fs from 'node:fs';
|
||||
import WavEncoder from 'wav-encoder';
|
||||
import { evalScope } from '@strudel/core';
|
||||
import { miniAllStrings } from '@strudel/mini';
|
||||
import { Dough } from './dough.mjs';
|
||||
|
||||
await evalScope(
|
||||
import('@strudel/core'),
|
||||
import('@strudel/mini'),
|
||||
import('@strudel/tonal'),
|
||||
// import('@strudel/tonal'),
|
||||
);
|
||||
|
||||
miniAllStrings(); // allows using single quotes for mini notation / skip transpilation
|
||||
|
||||
let sampleRate = 48000,
|
||||
cps = 0.4;
|
||||
|
||||
/* await doughsamples('github:eddyflux/crate');
|
||||
await doughsamples('github:eddyflux/wax'); */
|
||||
|
||||
let pat = note('c,eb,g,<bb c4 d4 eb4>')
|
||||
.s('sine')
|
||||
.press()
|
||||
.add(note(24))
|
||||
.fmi(3)
|
||||
.fmh(5.01)
|
||||
.dec(0.4)
|
||||
.delay('.6:<.12 .22>:.8')
|
||||
.jux(press)
|
||||
.rarely(add(note('12')))
|
||||
.lpf(400)
|
||||
.lpq(0.2)
|
||||
.lpd(0.4)
|
||||
.lpenv(3)
|
||||
.fmdecay(0.4)
|
||||
.fmenv(1)
|
||||
.postgain(0.6)
|
||||
.stack(s('<pink white>*8').dec(0.07).rarely(ply('2')).delay(0.5).hpf(sine.range(200, 2000).slow(4)).hpq(0.2))
|
||||
.stack(
|
||||
s('[- white@3]*2')
|
||||
.dec(0.4)
|
||||
.hpf('<2000!3 <4000 8000>>*4')
|
||||
.hpq(0.6)
|
||||
.ply('<1 2>*4')
|
||||
.postgain(0.5)
|
||||
.delay(0.5)
|
||||
.jux(rev)
|
||||
.lpf(5000),
|
||||
)
|
||||
.stack(
|
||||
note('<c2 - [- f1] ->*2')
|
||||
.s('square')
|
||||
.lpf(sine.range(100, 300).slow(4))
|
||||
.lpe(1)
|
||||
.segment(8)
|
||||
.lpd(0.3)
|
||||
.lpq(0.2)
|
||||
.dec(0.2)
|
||||
.speed('<1 2>')
|
||||
.ply('<1 2>')
|
||||
.postgain(1),
|
||||
)
|
||||
.stack(
|
||||
chord('<Cm Cm7 Cm9 Cm11 Fm Fm7 Fm9 Fm11>')
|
||||
.voicing()
|
||||
.s('<sine>')
|
||||
.clip(1)
|
||||
.rel(0.4)
|
||||
.vib('4:.2')
|
||||
.gain(0.7)
|
||||
.hpf(1200)
|
||||
.fm(0.5)
|
||||
.att(1)
|
||||
.lpa(0.5)
|
||||
.lpf(200)
|
||||
.lpenv(4)
|
||||
.chorus(0.8),
|
||||
)
|
||||
.slow(1 / cps);
|
||||
|
||||
let cycles = 30;
|
||||
let seconds = cycles + 1; // 1s release tail
|
||||
const haps = pat.queryArc(0, cycles);
|
||||
|
||||
const dough = new Dough(sampleRate);
|
||||
|
||||
console.log('spawn voices...');
|
||||
haps.forEach((hap) => {
|
||||
hap.value._begin = Number(hap.whole.begin);
|
||||
hap.value._duration = hap.duration /* / cps */;
|
||||
dough.scheduleSpawn(hap.value);
|
||||
});
|
||||
console.log(`render ${seconds}s long buffer, each dot is 1 second:`);
|
||||
const buffers = [new Float32Array(seconds * sampleRate), new Float32Array(seconds * sampleRate)];
|
||||
let t = performance.now();
|
||||
while (dough.t <= buffers[0].length) {
|
||||
dough.update();
|
||||
buffers[0][dough.t] = dough.out[0];
|
||||
buffers[1][dough.t] = dough.out[1];
|
||||
if (dough.t % sampleRate === 0) {
|
||||
process.stdout.write('.');
|
||||
}
|
||||
}
|
||||
const took = (performance.now() - t) / 1000;
|
||||
const load = (took / seconds) * 100;
|
||||
const speed = (seconds / took).toFixed(2);
|
||||
console.log('');
|
||||
console.log(`done!
|
||||
rendered ${seconds}s in ${took.toFixed(2)}s
|
||||
speed: ${speed}x
|
||||
load: ${load.toFixed(2)}%`);
|
||||
|
||||
const patternAudio = {
|
||||
sampleRate,
|
||||
channelData: buffers,
|
||||
};
|
||||
|
||||
WavEncoder.encode(patternAudio).then((buffer) => {
|
||||
fs.writeFileSync('pattern.wav', new Float32Array(buffer));
|
||||
});
|
||||
@@ -1,39 +0,0 @@
|
||||
import { Dough } from './dough.mjs';
|
||||
|
||||
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
|
||||
|
||||
class DoughProcessor extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
super();
|
||||
this.dough = new Dough(sampleRate, currentTime);
|
||||
this.port.onmessage = (event) => {
|
||||
if (event.data.spawn) {
|
||||
this.dough.scheduleSpawn(event.data.spawn);
|
||||
} else if (event.data.sample) {
|
||||
this.dough.loadSample(event.data.sample, event.data.channels, event.data.sampleRate);
|
||||
} else if (event.data.samples) {
|
||||
event.data.samples.forEach(([name, channels, sampleRate]) => {
|
||||
this.dough.loadSample(name, channels, sampleRate);
|
||||
});
|
||||
} else {
|
||||
console.log('unrecognized event type', event.data);
|
||||
}
|
||||
};
|
||||
}
|
||||
process(inputs, outputs, params) {
|
||||
if (this.disconnected) {
|
||||
return false;
|
||||
}
|
||||
const output = outputs[0];
|
||||
for (let i = 0; i < output[0].length; i++) {
|
||||
this.dough.update();
|
||||
for (let c = 0; c < output.length; c++) {
|
||||
//prevent speaker blowout via clipping if threshold exceeds
|
||||
output[c][i] = clamp(this.dough.out[c], -1, 1);
|
||||
}
|
||||
}
|
||||
return true; // keep the audio processing going
|
||||
}
|
||||
}
|
||||
|
||||
registerProcessor('dough-processor', DoughProcessor);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
// import _workletUrl from './dough-worklet.mjs?url'; // only for dev (breaks for production build)
|
||||
import _workletUrl from './dough-worklet.mjs?audioworklet'; // only for prod (breaks in development?!)
|
||||
|
||||
export * from './dough.mjs';
|
||||
export const workletUrl = _workletUrl;
|
||||
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"name": "supradough",
|
||||
"version": "1.2.4",
|
||||
"description": "platform agnostic synth and sampler intended for live coding. a reimplementation of superdough.",
|
||||
"main": "index.mjs",
|
||||
"type": "module",
|
||||
"publishConfig": {
|
||||
"main": "dist/index.mjs"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://codeberg.org/uzu/strudel.git"
|
||||
},
|
||||
"keywords": [
|
||||
"tidalcycles",
|
||||
"strudel",
|
||||
"pattern",
|
||||
"livecoding",
|
||||
"algorave"
|
||||
],
|
||||
"author": "Felix Roos <flix91@gmail.com>",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"bugs": {
|
||||
"url": "https://codeberg.org/uzu/strudel/issues"
|
||||
},
|
||||
"homepage": "https://codeberg.org/uzu/strudel#readme",
|
||||
"devDependencies": {
|
||||
"vite": "^6.0.11",
|
||||
"vite-plugin-bundle-audioworklet": "workspace:*",
|
||||
"wav-encoder": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import { resolve } from 'path';
|
||||
import bundleAudioWorkletPlugin from 'vite-plugin-bundle-audioworklet';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [bundleAudioWorkletPlugin()],
|
||||
build: {
|
||||
lib: {
|
||||
entry: resolve(__dirname, 'index.mjs'),
|
||||
formats: ['es'],
|
||||
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||
},
|
||||
target: 'esnext',
|
||||
},
|
||||
});
|
||||
@@ -3,6 +3,7 @@
|
||||
"version": "0.2.0",
|
||||
"private": true,
|
||||
"description": "Experimental Tidal Code interpreter",
|
||||
"main": "tidal.mjs",
|
||||
"module": "tidal.mjs",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -94,9 +94,6 @@ export function getWidgetID(widgetConfig) {
|
||||
|
||||
function widgetWithLocation(node, widgetConfig) {
|
||||
const id = getWidgetID(widgetConfig);
|
||||
// Store the unique ID back into the config so it's available for widget management
|
||||
// This is critical for block-based evaluation to match existing widgets with new ones
|
||||
widgetConfig.id = id;
|
||||
// add loc as identifier to first argument
|
||||
// the sliderWithID function is assumed to be sliderWithID(id, value, min?, max?)
|
||||
node.arguments.unshift({
|
||||
|
||||
@@ -7,5 +7,4 @@ This program is free software: you can redistribute it and/or modify it under th
|
||||
export * from './webaudio.mjs';
|
||||
export * from './scope.mjs';
|
||||
export * from './spectrum.mjs';
|
||||
export * from './supradough.mjs';
|
||||
export * from 'superdough';
|
||||
|
||||
@@ -35,8 +35,7 @@
|
||||
"dependencies": {
|
||||
"@strudel/core": "workspace:*",
|
||||
"@strudel/draw": "workspace:*",
|
||||
"superdough": "workspace:*",
|
||||
"supradough": "workspace:*"
|
||||
"superdough": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^6.0.11"
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
import { Pattern } from '@strudel/core';
|
||||
import { connectToDestination, getAudioContext, getWorklet } from 'superdough';
|
||||
|
||||
let doughWorklet;
|
||||
|
||||
function initDoughWorklet() {
|
||||
const ac = getAudioContext();
|
||||
doughWorklet = getWorklet(
|
||||
ac,
|
||||
'dough-processor',
|
||||
{},
|
||||
{
|
||||
outputChannelCount: [2],
|
||||
},
|
||||
);
|
||||
connectToDestination(doughWorklet); // channels?
|
||||
}
|
||||
|
||||
const soundMap = new Map();
|
||||
const loadedSounds = new Map();
|
||||
|
||||
Pattern.prototype.supradough = function () {
|
||||
return this.onSchedule((hap, begin, cps) => {
|
||||
hap.value._begin = begin;
|
||||
hap.value._duration = hap.duration / cps;
|
||||
!doughWorklet && initDoughWorklet();
|
||||
const s = (hap.value.bank ? hap.value.bank + '_' : '') + hap.value.s;
|
||||
const n = hap.value.n ?? 0;
|
||||
const soundKey = `${s}:${n}`;
|
||||
if (soundMap.has(s)) {
|
||||
hap.value.s = soundKey; // dough.mjs is unaware of bank and n (only maps keys to buffers)
|
||||
}
|
||||
if (soundMap.has(s) && !loadedSounds.has(soundKey)) {
|
||||
const urls = soundMap.get(s);
|
||||
const url = urls[n % urls.length];
|
||||
console.log(`load ${soundKey} from ${url}`);
|
||||
const loadSample = fetchSample(url);
|
||||
loadedSounds.set(soundKey, loadSample);
|
||||
loadSample.then(({ channels, sampleRate }) =>
|
||||
doughWorklet.port.postMessage({
|
||||
sample: soundKey,
|
||||
channels,
|
||||
sampleRate,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
doughWorklet.port.postMessage({ spawn: hap.value });
|
||||
}, 1);
|
||||
};
|
||||
|
||||
function githubPath(base, subpath = '') {
|
||||
if (!base.startsWith('github:')) {
|
||||
throw new Error('expected "github:" at the start of pseudoUrl');
|
||||
}
|
||||
let [_, path] = base.split('github:');
|
||||
path = path.endsWith('/') ? path.slice(0, -1) : path;
|
||||
if (path.split('/').length === 2) {
|
||||
// assume main as default branch if none set
|
||||
path += '/main';
|
||||
}
|
||||
return `https://raw.githubusercontent.com/${path}/${subpath}`;
|
||||
}
|
||||
export async function _fetchSampleMap(url) {
|
||||
if (url.startsWith('github:')) {
|
||||
url = githubPath(url, 'strudel.json');
|
||||
}
|
||||
if (url.startsWith('local:')) {
|
||||
url = `http://localhost:5432`;
|
||||
}
|
||||
if (url.startsWith('shabda:')) {
|
||||
let [_, path] = url.split('shabda:');
|
||||
url = `https://shabda.ndre.gr/${path}.json?strudel=1`;
|
||||
}
|
||||
if (url.startsWith('shabda/speech')) {
|
||||
let [_, path] = url.split('shabda/speech');
|
||||
path = path.startsWith('/') ? path.substring(1) : path;
|
||||
let [params, words] = path.split(':');
|
||||
let gender = 'f';
|
||||
let language = 'en-GB';
|
||||
if (params) {
|
||||
[language, gender] = params.split('/');
|
||||
}
|
||||
url = `https://shabda.ndre.gr/speech/${words}.json?gender=${gender}&language=${language}&strudel=1'`;
|
||||
}
|
||||
if (typeof fetch !== 'function') {
|
||||
// not a browser
|
||||
return;
|
||||
}
|
||||
const base = url.split('/').slice(0, -1).join('/');
|
||||
if (typeof fetch === 'undefined') {
|
||||
// skip fetch when in node / testing
|
||||
return;
|
||||
}
|
||||
const json = await fetch(url)
|
||||
.then((res) => res.json())
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
throw new Error(`error loading "${url}"`);
|
||||
});
|
||||
return [json, json._base || base];
|
||||
}
|
||||
|
||||
// for some reason, only piano and flute work.. is it because mp3??
|
||||
|
||||
async function fetchSample(url) {
|
||||
const buffer = await fetch(url)
|
||||
.then((res) => res.arrayBuffer())
|
||||
.then((buf) => getAudioContext().decodeAudioData(buf));
|
||||
let channels = [];
|
||||
for (let i = 0; i < buffer.numberOfChannels; i++) {
|
||||
channels.push(buffer.getChannelData(i));
|
||||
}
|
||||
return { channels, sampleRate: buffer.sampleRate };
|
||||
}
|
||||
|
||||
export async function supradoughsamples(sampleMap, baseUrl) {
|
||||
if (typeof sampleMap === 'string') {
|
||||
const [json, base] = await _fetchSampleMap(sampleMap);
|
||||
// console.log('json', json, 'base', base);
|
||||
return supradoughsamples(json, base);
|
||||
}
|
||||
Object.entries(sampleMap).map(async ([key, urls]) => {
|
||||
if (key !== '_base') {
|
||||
urls = urls.map((url) => baseUrl + url);
|
||||
// console.log('set', key, urls);
|
||||
soundMap.set(key, urls);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -17,10 +17,7 @@ import {
|
||||
resetGlobalEffects,
|
||||
errorLogger,
|
||||
} from 'superdough';
|
||||
import './supradough.mjs';
|
||||
import { workletUrl } from 'supradough';
|
||||
import { SuperdoughAudioController } from 'superdough/superdoughoutput.mjs';
|
||||
registerWorklet(workletUrl);
|
||||
|
||||
const { Pattern, logger, repl } = strudel;
|
||||
|
||||
|
||||
Generated
+3
-23
@@ -359,13 +359,13 @@ importers:
|
||||
|
||||
packages/hs2js:
|
||||
dependencies:
|
||||
tree-sitter-haskell:
|
||||
specifier: ^0.23.1
|
||||
version: 0.23.1(tree-sitter@0.21.1)
|
||||
web-tree-sitter:
|
||||
specifier: ^0.24.7
|
||||
version: 0.24.7
|
||||
devDependencies:
|
||||
tree-sitter-haskell:
|
||||
specifier: ^0.23.1
|
||||
version: 0.23.1(tree-sitter@0.21.1)
|
||||
vite:
|
||||
specifier: ^6.0.11
|
||||
version: 6.0.11(@types/node@22.10.10)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(yaml@2.7.0)
|
||||
@@ -606,18 +606,6 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../vite-plugin-bundle-audioworklet
|
||||
|
||||
packages/supradough:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^6.0.11
|
||||
version: 6.0.11(@types/node@22.10.10)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(yaml@2.7.0)
|
||||
vite-plugin-bundle-audioworklet:
|
||||
specifier: workspace:*
|
||||
version: link:../vite-plugin-bundle-audioworklet
|
||||
wav-encoder:
|
||||
specifier: ^1.3.0
|
||||
version: 1.3.0
|
||||
|
||||
packages/tidal:
|
||||
dependencies:
|
||||
'@strudel/core':
|
||||
@@ -729,9 +717,6 @@ importers:
|
||||
superdough:
|
||||
specifier: workspace:*
|
||||
version: link:../superdough
|
||||
supradough:
|
||||
specifier: workspace:*
|
||||
version: link:../supradough
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^6.0.11
|
||||
@@ -7782,9 +7767,6 @@ packages:
|
||||
walk-up-path@3.0.1:
|
||||
resolution: {integrity: sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==}
|
||||
|
||||
wav-encoder@1.3.0:
|
||||
resolution: {integrity: sha512-FXJdEu2qDOI+wbVYZpu21CS1vPEg5NaxNskBr4SaULpOJMrLE6xkH8dECa7PiS+ZoeyvP7GllWUAxPN3AvFSEw==}
|
||||
|
||||
wav@1.0.2:
|
||||
resolution: {integrity: sha512-viHtz3cDd/Tcr/HbNqzQCofKdF6kWUymH9LGDdskfWFoIy/HJ+RTihgjEcHfnsy1PO4e9B+y4HwgTwMrByquhg==}
|
||||
|
||||
@@ -16365,8 +16347,6 @@ snapshots:
|
||||
|
||||
walk-up-path@3.0.1: {}
|
||||
|
||||
wav-encoder@1.3.0: {}
|
||||
|
||||
wav@1.0.2:
|
||||
dependencies:
|
||||
buffer-alloc: 1.2.0
|
||||
|
||||
@@ -3175,43 +3175,6 @@ exports[`runs examples > example "delayfeedback" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "delayspeed" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 1/8 → 1/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 1/4 → 3/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 3/8 → 1/2 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 1/2 → 5/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 5/8 → 3/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 3/4 → 7/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 7/8 → 1/1 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 1/1 → 9/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 9/8 → 5/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 5/4 → 11/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 11/8 → 3/2 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 3/2 → 13/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 13/8 → 7/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 7/4 → 15/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 15/8 → 2/1 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 2/1 → 17/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 17/8 → 9/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 9/4 → 19/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 19/8 → 5/2 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 5/2 → 21/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 21/8 → 11/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 11/4 → 23/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 23/8 → 3/1 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 3/1 → 25/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 25/8 → 13/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 13/4 → 27/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 27/8 → 7/2 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 7/2 → 29/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 29/8 → 15/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 15/4 → 31/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 31/8 → 4/1 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "delaysync" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/2 | s:bd delay:0.25 delaysync:0.125 ]",
|
||||
@@ -3227,38 +3190,38 @@ exports[`runs examples > example "delaysync" example index 0 1`] = `
|
||||
|
||||
exports[`runs examples > example "delaytime" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 1/8 → 1/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 1/4 → 3/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 3/8 → 1/2 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 1/2 → 5/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 5/8 → 3/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 3/4 → 7/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 7/8 → 1/1 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]",
|
||||
"[ 1/1 → 9/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 9/8 → 5/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 5/4 → 11/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 11/8 → 3/2 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 3/2 → 13/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 13/8 → 7/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 7/4 → 15/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 15/8 → 2/1 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:0.5 ]",
|
||||
"[ 2/1 → 17/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 17/8 → 9/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 9/4 → 19/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 19/8 → 5/2 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 5/2 → 21/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 21/8 → 11/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 11/4 → 23/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 23/8 → 3/1 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-1 ]",
|
||||
"[ 3/1 → 25/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 25/8 → 13/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 13/4 → 27/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 27/8 → 7/2 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 7/2 → 29/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 29/8 → 15/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 15/4 → 31/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 31/8 → 4/1 | note:a s:sawtooth delay:0.8 delaytime:0.5 delayspeed:-2 ]",
|
||||
"[ 0/1 → 1/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 1/8 → 1/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 1/4 → 3/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 3/8 → 1/2 | note:a s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 1/2 → 5/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 5/8 → 3/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 3/4 → 7/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 7/8 → 1/1 | note:a s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 1/1 → 9/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 9/8 → 5/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 5/4 → 11/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 11/8 → 3/2 | note:a s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 3/2 → 13/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 13/8 → 7/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 7/4 → 15/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 15/8 → 2/1 | note:a s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 2/1 → 17/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 17/8 → 9/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 9/4 → 19/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 19/8 → 5/2 | note:a s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 5/2 → 21/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 21/8 → 11/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 11/4 → 23/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 23/8 → 3/1 | note:a s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 3/1 → 25/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 25/8 → 13/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 13/4 → 27/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 27/8 → 7/2 | note:a s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 7/2 → 29/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 29/8 → 15/4 | note:d s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 15/4 → 31/8 | note:a# s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
"[ 31/8 → 4/1 | note:a s:sawtooth delay:0.8 delaytime:0.5 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ export default defineConfig({
|
||||
/^https:\/\/freesound\.org\/.*/i,
|
||||
/^https:\/\/cdn\.freesound\.org\/.*/i,
|
||||
/^https:\/\/shabda\.ndre\.gr\/.*/i,
|
||||
/^https:\/\/felixroos\.github\.io\/webaudiofontdata\/.*/i,
|
||||
].some((regex) => regex.test(url)),
|
||||
handler: 'CacheFirst',
|
||||
options: {
|
||||
|
||||
@@ -5,9 +5,8 @@ import { Textbox } from '@src/repl/components/panel/SettingsTab';
|
||||
import { settingsMap, useSettings } from '@src/settings.mjs';
|
||||
|
||||
const isValid = ({ name, description, tags = [] }) => {
|
||||
const isSupradoughOnly = tags.includes('supradough') && !tags.includes('superdough');
|
||||
const isSuperdirtOnly = tags.includes('superdirt') && !tags.includes('superdough');
|
||||
return name && !name.startsWith('_') && !!description && !isSupradoughOnly && !isSuperdirtOnly;
|
||||
return name && !name.startsWith('_') && !!description && !isSuperdirtOnly;
|
||||
};
|
||||
|
||||
const availableFunctions = (() => {
|
||||
@@ -38,7 +37,7 @@ const availableFunctions = (() => {
|
||||
})();
|
||||
|
||||
const tagCounts = {};
|
||||
const ignoredTags = ['supradough', 'superdirt'];
|
||||
const ignoredTags = ['superdirt'];
|
||||
// const tagOptions = { all: `all (${availableFunctions.length})` };
|
||||
const tagOptions = { all: `all` };
|
||||
for (const doc of availableFunctions) {
|
||||
|
||||
Reference in New Issue
Block a user