Merge remote-tracking branch 'origin/main' into supradough
This commit is contained in:
commit
30f7127a92
10 changed files with 204 additions and 38 deletions
|
|
@ -3192,6 +3192,25 @@ export const slice = register(
|
|||
false, // turns off auto-patternification
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* make something happen on event time
|
||||
* uses browser timeout which is innacurate for audio tasks
|
||||
* @name onTriggerTime
|
||||
* @memberof Pattern
|
||||
* @returns Pattern
|
||||
* @example
|
||||
* s("bd!8").onTriggerTime((hap) => {console.info(hap)})
|
||||
*/
|
||||
Pattern.prototype.onTriggerTime = function (func) {
|
||||
return this.onTrigger((t_deprecate, hap, currentTime, cps = 1, targetTime) => {
|
||||
const diff = targetTime - currentTime;
|
||||
window.setTimeout(() => {
|
||||
func(hap);
|
||||
}, diff * 1000);
|
||||
}, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Works the same as slice, but changes the playback speed of each slice to match the duration of its step.
|
||||
* @name splice
|
||||
|
|
|
|||
|
|
@ -486,13 +486,34 @@ export const wchooseCycles = (...pairs) => _wchooseWith(rand.segment(1), ...pair
|
|||
|
||||
export const wrandcat = wchooseCycles;
|
||||
|
||||
// this function expects pat to be a pattern of floats...
|
||||
export const perlinWith = (pat) => {
|
||||
const pata = pat.fmap(Math.floor);
|
||||
const patb = pat.fmap((t) => Math.floor(t) + 1);
|
||||
function _perlin(t) {
|
||||
let ta = Math.floor(t);
|
||||
let tb = ta + 1;
|
||||
const smootherStep = (x) => 6.0 * x ** 5 - 15.0 * x ** 4 + 10.0 * x ** 3;
|
||||
const interp = (x) => (a) => (b) => a + smootherStep(x) * (b - a);
|
||||
return pat.sub(pata).fmap(interp).appBoth(pata.fmap(timeToRand)).appBoth(patb.fmap(timeToRand));
|
||||
const v = interp(t - ta)(timeToRand(ta))(timeToRand(tb));
|
||||
return v;
|
||||
}
|
||||
export const perlinWith = (tpat) => {
|
||||
return tpat.fmap(_perlin);
|
||||
};
|
||||
|
||||
function _berlin(t) {
|
||||
const prevRidgeStartIndex = Math.floor(t);
|
||||
const nextRidgeStartIndex = prevRidgeStartIndex + 1;
|
||||
|
||||
const prevRidgeBottomPoint = timeToRand(prevRidgeStartIndex);
|
||||
const nextRidgeTopPoint = timeToRand(nextRidgeStartIndex) + prevRidgeBottomPoint;
|
||||
|
||||
const currentPercent = (t - prevRidgeStartIndex) / (nextRidgeStartIndex - prevRidgeStartIndex);
|
||||
const interp = (a, b, t) => {
|
||||
return a + (b - a) * t;
|
||||
};
|
||||
return interp(prevRidgeBottomPoint, nextRidgeTopPoint, currentPercent) / 2;
|
||||
}
|
||||
|
||||
export const berlinWith = (tpat) => {
|
||||
return tpat.fmap(_berlin);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -506,6 +527,18 @@ export const perlinWith = (pat) => {
|
|||
*/
|
||||
export const perlin = perlinWith(time.fmap((v) => Number(v)));
|
||||
|
||||
/**
|
||||
* Generates a continuous pattern of [berlin noise](conceived by Jame Coyne and Jade Rowland as a joke but turned out to be surprisingly cool and useful,
|
||||
* like perlin noise but with sawtooth waves), in the range 0..1.
|
||||
*
|
||||
* @name berlin
|
||||
* @example
|
||||
* // ascending arpeggios
|
||||
* n("0!16".add(berlin.fast(4).mul(14))).scale("d:minor")
|
||||
*
|
||||
*/
|
||||
export const berlin = berlinWith(time.fmap((v) => Number(v)));
|
||||
|
||||
export const degradeByWith = register(
|
||||
'degradeByWith',
|
||||
(withPat, x, pat) => pat.fmap((a) => (_) => a).appLeft(withPat.filterValues((v) => v > x)),
|
||||
|
|
|
|||
|
|
@ -882,7 +882,6 @@ class ByteBeatProcessor extends AudioWorkletProcessor {
|
|||
const funcValue = this.func(local_t);
|
||||
let signal = (funcValue & 255) / 127.5 - 1;
|
||||
const out = signal * 0.2;
|
||||
|
||||
for (let c = 0; c < output.length; c++) {
|
||||
//prevent speaker blowout via clipping if threshold exceeds
|
||||
output[c][i] = clamp(out, -0.4, 0.4);
|
||||
|
|
|
|||
|
|
@ -1051,6 +1051,75 @@ exports[`runs examples > example "begin" example index 0 1`] = `
|
|||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "berlin" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/16 | note:D3 ]",
|
||||
"[ 1/16 → 1/8 | note:E3 ]",
|
||||
"[ 1/8 → 3/16 | note:F3 ]",
|
||||
"[ 3/16 → 1/4 | note:G3 ]",
|
||||
"[ 1/4 → 5/16 | note:A3 ]",
|
||||
"[ 5/16 → 3/8 | note:C4 ]",
|
||||
"[ 3/8 → 7/16 | note:D4 ]",
|
||||
"[ 7/16 → 1/2 | note:F4 ]",
|
||||
"[ 1/2 → 9/16 | note:D4 ]",
|
||||
"[ 9/16 → 5/8 | note:E4 ]",
|
||||
"[ 5/8 → 11/16 | note:E4 ]",
|
||||
"[ 11/16 → 3/4 | note:E4 ]",
|
||||
"[ 3/4 → 13/16 | note:F3 ]",
|
||||
"[ 13/16 → 7/8 | note:F3 ]",
|
||||
"[ 7/8 → 15/16 | note:F3 ]",
|
||||
"[ 15/16 → 1/1 | note:F3 ]",
|
||||
"[ 1/1 → 17/16 | note:E3 ]",
|
||||
"[ 17/16 → 9/8 | note:E3 ]",
|
||||
"[ 9/8 → 19/16 | note:E3 ]",
|
||||
"[ 19/16 → 5/4 | note:F3 ]",
|
||||
"[ 5/4 → 21/16 | note:E3 ]",
|
||||
"[ 21/16 → 11/8 | note:F3 ]",
|
||||
"[ 11/8 → 23/16 | note:G3 ]",
|
||||
"[ 23/16 → 3/2 | note:A3 ]",
|
||||
"[ 3/2 → 25/16 | note:A3 ]",
|
||||
"[ 25/16 → 13/8 | note:Bb3 ]",
|
||||
"[ 13/8 → 27/16 | note:Bb3 ]",
|
||||
"[ 27/16 → 7/4 | note:Bb3 ]",
|
||||
"[ 7/4 → 29/16 | note:F3 ]",
|
||||
"[ 29/16 → 15/8 | note:G3 ]",
|
||||
"[ 15/8 → 31/16 | note:Bb3 ]",
|
||||
"[ 31/16 → 2/1 | note:C4 ]",
|
||||
"[ 2/1 → 33/16 | note:C4 ]",
|
||||
"[ 33/16 → 17/8 | note:D4 ]",
|
||||
"[ 17/8 → 35/16 | note:F4 ]",
|
||||
"[ 35/16 → 9/4 | note:G4 ]",
|
||||
"[ 9/4 → 37/16 | note:Bb3 ]",
|
||||
"[ 37/16 → 19/8 | note:Bb3 ]",
|
||||
"[ 19/8 → 39/16 | note:Bb3 ]",
|
||||
"[ 39/16 → 5/2 | note:C4 ]",
|
||||
"[ 5/2 → 41/16 | note:F3 ]",
|
||||
"[ 41/16 → 21/8 | note:F3 ]",
|
||||
"[ 21/8 → 43/16 | note:G3 ]",
|
||||
"[ 43/16 → 11/4 | note:A3 ]",
|
||||
"[ 11/4 → 45/16 | note:A3 ]",
|
||||
"[ 45/16 → 23/8 | note:A3 ]",
|
||||
"[ 23/8 → 47/16 | note:A3 ]",
|
||||
"[ 47/16 → 3/1 | note:A3 ]",
|
||||
"[ 3/1 → 49/16 | note:E3 ]",
|
||||
"[ 49/16 → 25/8 | note:G3 ]",
|
||||
"[ 25/8 → 51/16 | note:Bb3 ]",
|
||||
"[ 51/16 → 13/4 | note:C4 ]",
|
||||
"[ 13/4 → 53/16 | note:D4 ]",
|
||||
"[ 53/16 → 27/8 | note:E4 ]",
|
||||
"[ 27/8 → 55/16 | note:G4 ]",
|
||||
"[ 55/16 → 7/2 | note:A4 ]",
|
||||
"[ 7/2 → 57/16 | note:Bb3 ]",
|
||||
"[ 57/16 → 29/8 | note:Bb3 ]",
|
||||
"[ 29/8 → 59/16 | note:C4 ]",
|
||||
"[ 59/16 → 15/4 | note:C4 ]",
|
||||
"[ 15/4 → 61/16 | note:F3 ]",
|
||||
"[ 61/16 → 31/8 | note:G3 ]",
|
||||
"[ 31/8 → 63/16 | note:G3 ]",
|
||||
"[ 63/16 → 4/1 | note:A3 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "binary" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/3 | s:hh ]",
|
||||
|
|
@ -5950,6 +6019,43 @@ exports[`runs examples > example "often" example index 0 1`] = `
|
|||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "onTriggerTime" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/8 | s:bd ]",
|
||||
"[ 1/8 → 1/4 | s:bd ]",
|
||||
"[ 1/4 → 3/8 | s:bd ]",
|
||||
"[ 3/8 → 1/2 | s:bd ]",
|
||||
"[ 1/2 → 5/8 | s:bd ]",
|
||||
"[ 5/8 → 3/4 | s:bd ]",
|
||||
"[ 3/4 → 7/8 | s:bd ]",
|
||||
"[ 7/8 → 1/1 | s:bd ]",
|
||||
"[ 1/1 → 9/8 | s:bd ]",
|
||||
"[ 9/8 → 5/4 | s:bd ]",
|
||||
"[ 5/4 → 11/8 | s:bd ]",
|
||||
"[ 11/8 → 3/2 | s:bd ]",
|
||||
"[ 3/2 → 13/8 | s:bd ]",
|
||||
"[ 13/8 → 7/4 | s:bd ]",
|
||||
"[ 7/4 → 15/8 | s:bd ]",
|
||||
"[ 15/8 → 2/1 | s:bd ]",
|
||||
"[ 2/1 → 17/8 | s:bd ]",
|
||||
"[ 17/8 → 9/4 | s:bd ]",
|
||||
"[ 9/4 → 19/8 | s:bd ]",
|
||||
"[ 19/8 → 5/2 | s:bd ]",
|
||||
"[ 5/2 → 21/8 | s:bd ]",
|
||||
"[ 21/8 → 11/4 | s:bd ]",
|
||||
"[ 11/4 → 23/8 | s:bd ]",
|
||||
"[ 23/8 → 3/1 | s:bd ]",
|
||||
"[ 3/1 → 25/8 | s:bd ]",
|
||||
"[ 25/8 → 13/4 | s:bd ]",
|
||||
"[ 13/4 → 27/8 | s:bd ]",
|
||||
"[ 27/8 → 7/2 | s:bd ]",
|
||||
"[ 7/2 → 29/8 | s:bd ]",
|
||||
"[ 29/8 → 15/4 | s:bd ]",
|
||||
"[ 15/4 → 31/8 | s:bd ]",
|
||||
"[ 31/8 → 4/1 | s:bd ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "orbit" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/6 | s:hh delay:0.5 delaytime:0.25 orbit:1 ]",
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ export const SIDEBAR: Sidebar = {
|
|||
{ text: 'What is Strudel?', link: 'workshop/getting-started' },
|
||||
{ text: 'Showcase', link: 'intro/showcase' },
|
||||
{ text: 'Blog', link: 'blog' },
|
||||
{ text: 'Community Bakery', link: 'bakery' },
|
||||
/* { text: 'Community Bakery', link: 'bakery' }, */
|
||||
],
|
||||
Workshop: [
|
||||
// { text: 'Getting Started', link: 'workshop/getting-started' },
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ export function Header({ context, embedded = false }) {
|
|||
>
|
||||
{!isEmbedded && <span>update</span>}
|
||||
</button>
|
||||
{!isEmbedded && (
|
||||
{/* !isEmbedded && (
|
||||
<button
|
||||
title="shuffle"
|
||||
className="hover:opacity-50 p-2 flex items-center space-x-1"
|
||||
|
|
@ -101,8 +101,8 @@ export function Header({ context, embedded = false }) {
|
|||
>
|
||||
<span> shuffle</span>
|
||||
</button>
|
||||
)}
|
||||
{!isEmbedded && (
|
||||
) */}
|
||||
{/* !isEmbedded && (
|
||||
<button
|
||||
title="share"
|
||||
className={cx(
|
||||
|
|
@ -113,7 +113,7 @@ export function Header({ context, embedded = false }) {
|
|||
>
|
||||
<span>share</span>
|
||||
</button>
|
||||
)}
|
||||
) */}
|
||||
{!isEmbedded && (
|
||||
<a
|
||||
title="learn"
|
||||
|
|
|
|||
|
|
@ -142,21 +142,21 @@ function UserPatterns({ context }) {
|
|||
</div>
|
||||
|
||||
<div className="overflow-auto h-full bg-background p-2 rounded-md">
|
||||
{patternFilter === patternFilterName.user && (
|
||||
<PatternButtons
|
||||
onClick={(id) =>
|
||||
updateCodeWindow(
|
||||
context,
|
||||
{ ...userPatterns[id], collection: userPattern.collection },
|
||||
autoResetPatternOnChange,
|
||||
)
|
||||
}
|
||||
patterns={userPatterns}
|
||||
started={context.started}
|
||||
activePattern={activePattern}
|
||||
viewingPatternID={viewingPatternID}
|
||||
/>
|
||||
)}
|
||||
{/* {patternFilter === patternFilterName.user && ( */}
|
||||
<PatternButtons
|
||||
onClick={(id) =>
|
||||
updateCodeWindow(
|
||||
context,
|
||||
{ ...userPatterns[id], collection: userPattern.collection },
|
||||
autoResetPatternOnChange,
|
||||
)
|
||||
}
|
||||
patterns={userPatterns}
|
||||
started={context.started}
|
||||
activePattern={activePattern}
|
||||
viewingPatternID={viewingPatternID}
|
||||
/>
|
||||
{/* )} */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -250,6 +250,11 @@ export function PatternsTab({ context }) {
|
|||
const { patternFilter } = useSettings();
|
||||
|
||||
return (
|
||||
<div className="px-4 w-full text-foreground space-y-2 flex flex-col overflow-hidden max-h-full h-full">
|
||||
<UserPatterns context={context} />
|
||||
</div>
|
||||
);
|
||||
/* return (
|
||||
<div className="px-4 w-full text-foreground space-y-2 flex flex-col overflow-hidden max-h-full h-full">
|
||||
<ButtonGroup
|
||||
value={patternFilter}
|
||||
|
|
@ -263,5 +268,5 @@ export function PatternsTab({ context }) {
|
|||
<PublicPatterns context={context} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
); */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,17 +15,18 @@ export function WelcomeTab({ context }) {
|
|||
<br />
|
||||
<span className="underline">1. hit play</span> - <span className="underline">2. change something</span> -{' '}
|
||||
<span className="underline">3. hit update</span>
|
||||
<br />
|
||||
If you don't like what you hear, try <span className="underline">shuffle</span>!
|
||||
{/* <br />
|
||||
If you don't like what you hear, try <span className="underline">shuffle</span>! */}
|
||||
</p>
|
||||
<p>
|
||||
To learn more about what this all means, check out the{' '}
|
||||
{/* To learn more about what this all means, check out the{' '} */}
|
||||
To get started, check out the
|
||||
<a href={`${baseNoTrailing}/workshop/getting-started/`} target="_blank">
|
||||
interactive tutorial
|
||||
</a>
|
||||
. Also feel free to join the{' '}
|
||||
<a href="https://discord.com/invite/HGEdXmRkzT" target="_blank">
|
||||
tidalcycles discord channel
|
||||
discord channel
|
||||
</a>{' '}
|
||||
to ask any questions, give feedback or just say hello.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ async function getModule(name) {
|
|||
return modules.find((m) => m.packageName === name);
|
||||
}
|
||||
|
||||
const initialCode = `// LOADING`;
|
||||
|
||||
export function useReplContext() {
|
||||
const { isSyncEnabled, audioEngineTarget } = useSettings();
|
||||
const shouldUseWebaudio = audioEngineTarget !== audioEngineTargets.osc;
|
||||
|
|
@ -77,7 +79,7 @@ export function useReplContext() {
|
|||
transpiler,
|
||||
autodraw: false,
|
||||
root: containerRef.current,
|
||||
initialCode: '// LOADING',
|
||||
initialCode,
|
||||
pattern: silence,
|
||||
drawTime,
|
||||
drawContext,
|
||||
|
|
@ -133,9 +135,10 @@ export function useReplContext() {
|
|||
code = latestCode;
|
||||
msg = `Your last session has been loaded!`;
|
||||
} else {
|
||||
const { code: randomTune, name } = await getRandomTune();
|
||||
code = randomTune;
|
||||
msg = `A random code snippet named "${name}" has been loaded!`;
|
||||
/* const { code: randomTune, name } = await getRandomTune();
|
||||
code = randomTune; */
|
||||
code = '$: s("[bd <hh oh>]*2").bank("tr909").dec(.4)';
|
||||
msg = `Default code has been loaded`;
|
||||
}
|
||||
editor.setCode(code);
|
||||
setDocumentTitle(code);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import './Repl.css';
|
|||
import { createClient } from '@supabase/supabase-js';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { writeText } from '@tauri-apps/plugin-clipboard-manager';
|
||||
import { $featuredPatterns, loadDBPatterns } from '@src/user_pattern_utils.mjs';
|
||||
import { $featuredPatterns /* , loadDBPatterns */ } from '@src/user_pattern_utils.mjs';
|
||||
|
||||
// Create a single supabase client for interacting with your database
|
||||
export const supabase = createClient(
|
||||
|
|
@ -16,9 +16,9 @@ export const supabase = createClient(
|
|||
);
|
||||
|
||||
let dbLoaded;
|
||||
if (typeof window !== 'undefined') {
|
||||
/* if (typeof window !== 'undefined') {
|
||||
dbLoaded = loadDBPatterns();
|
||||
}
|
||||
} */
|
||||
|
||||
export async function initCode() {
|
||||
// load code from url hash (either short hash from database or decode long hash)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue