Merge commit '85d3d7392ecfdc985fa8cc93e01846bec0f16dc4' into talk

This commit is contained in:
Felix Roos
2022-07-01 13:05:32 +02:00
53 changed files with 290 additions and 121 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+119 -116
View File
@@ -108,6 +108,7 @@ function App() {
pattern,
pushLog,
pending,
hideHeader,
} = useRepl({
tune: '// LOADING...',
defaultSynth,
@@ -167,128 +168,130 @@ function App() {
return (
<div className="min-h-screen flex flex-col">
<header
id="header"
className={cx(
'flex-none w-full px-2 flex border-b border-gray-200 justify-between z-[10] bg-gray-100',
isEmbedded ? 'h-8' : 'h-14',
)}
>
<div className="flex items-center space-x-2">
<img src={logo} className={cx('Tidal-logo', isEmbedded ? 'w-6 h-6' : 'w-10 h-10')} alt="logo" />
<h1 className={isEmbedded ? 'text-l' : 'text-xl'}>Strudel {isEmbedded ? 'Mini ' : ''}REPL</h1>
</div>
<div className="flex">
<button
onClick={() => {
getAudioContext().resume(); // fixes no sound in ios webkit
togglePlay();
}}
className={cx('hover:bg-gray-300', !isEmbedded ? 'p-2' : 'px-2')}
>
{!pending ? (
<span className={cx('flex items-center', isEmbedded ? 'w-16' : 'w-16')}>
{cycle.started ? (
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z"
clipRule="evenodd"
/>
</svg>
) : (
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z"
clipRule="evenodd"
/>
</svg>
)}
{cycle.started ? 'pause' : 'play'}
</span>
) : (
<>loading...</>
)}
</button>
{!isEmbedded && (
{!hideHeader && (
<header
id="header"
className={cx(
'flex-none w-full px-2 flex border-b border-gray-200 justify-between z-[10] bg-gray-100',
isEmbedded ? 'h-8' : 'h-14',
)}
>
<div className="flex items-center space-x-2">
<img src={logo} className={cx('Tidal-logo', isEmbedded ? 'w-6 h-6' : 'w-10 h-10')} alt="logo" />
<h1 className={isEmbedded ? 'text-l' : 'text-xl'}>Strudel {isEmbedded ? 'Mini ' : ''}REPL</h1>
</div>
<div className="flex">
<button
className="hover:bg-gray-300 p-2"
onClick={async () => {
const _code = getRandomTune();
console.log('tune', _code); // uncomment this to debug when random code fails
setCode(_code);
cleanupDraw();
cleanupUi();
resetLoadedSamples();
prebake();
const parsed = await evaluate(_code);
setPattern(parsed.pattern);
setActiveCode(_code);
onClick={() => {
getAudioContext().resume(); // fixes no sound in ios webkit
togglePlay();
}}
className={cx('hover:bg-gray-300', !isEmbedded ? 'p-2' : 'px-2')}
>
🎲 random
{!pending ? (
<span className={cx('flex items-center', isEmbedded ? 'w-16' : 'w-16')}>
{cycle.started ? (
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z"
clipRule="evenodd"
/>
</svg>
) : (
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z"
clipRule="evenodd"
/>
</svg>
)}
{cycle.started ? 'pause' : 'play'}
</span>
) : (
<>loading...</>
)}
</button>
)}
{!isEmbedded && (
<button className={cx('hover:bg-gray-300', !isEmbedded ? 'p-2' : 'px-2')}>
<a href="./tutorial">📚 tutorial</a>
</button>
)}
{!isEmbedded && (
<button
className={cx('cursor-pointer hover:bg-gray-300', !isEmbedded ? 'p-2' : 'px-2')}
onClick={async () => {
const codeToShare = activeCode || code;
if (lastShared === codeToShare) {
// alert('Link already generated!');
pushLog(`Link already generated!`);
return;
}
// generate uuid in the browser
const hash = nanoid(12);
const { data, error } = await supabase.from('code').insert([{ code: codeToShare, hash }]);
if (!error) {
setLastShared(activeCode || code);
const shareUrl = window.location.origin + '?' + hash;
// copy shareUrl to clipboard
navigator.clipboard.writeText(shareUrl);
const message = `Link copied to clipboard: ${shareUrl}`;
// alert(message);
pushLog(message);
} else {
console.log('error', error);
const message = `Error: ${error.message}`;
// alert(message);
pushLog(message);
}
}}
>
📣 share{lastShared && lastShared === (activeCode || code) ? 'd!' : ''}
</button>
)}
{isEmbedded && (
<button className={cx('hover:bg-gray-300 px-2')}>
<a href={window.location.href} target="_blank" rel="noopener noreferrer" title="Open in REPL">
🚀 open
</a>
</button>
)}
{isEmbedded && (
<button className={cx('hover:bg-gray-300 px-2')}>
<a
onClick={() => {
window.location.href = initialUrl;
window.location.reload();
{!isEmbedded && (
<button
className="hover:bg-gray-300 p-2"
onClick={async () => {
const _code = getRandomTune();
console.log('tune', _code); // uncomment this to debug when random code fails
setCode(_code);
cleanupDraw();
cleanupUi();
resetLoadedSamples();
prebake();
const parsed = await evaluate(_code);
setPattern(parsed.pattern);
setActiveCode(_code);
}}
title="Reset"
>
💔 reset
</a>
</button>
)}
</div>
</header>
🎲 random
</button>
)}
{!isEmbedded && (
<button className={cx('hover:bg-gray-300', !isEmbedded ? 'p-2' : 'px-2')}>
<a href="./tutorial">📚 tutorial</a>
</button>
)}
{!isEmbedded && (
<button
className={cx('cursor-pointer hover:bg-gray-300', !isEmbedded ? 'p-2' : 'px-2')}
onClick={async () => {
const codeToShare = activeCode || code;
if (lastShared === codeToShare) {
// alert('Link already generated!');
pushLog(`Link already generated!`);
return;
}
// generate uuid in the browser
const hash = nanoid(12);
const { data, error } = await supabase.from('code').insert([{ code: codeToShare, hash }]);
if (!error) {
setLastShared(activeCode || code);
const shareUrl = window.location.origin + '?' + hash;
// copy shareUrl to clipboard
navigator.clipboard.writeText(shareUrl);
const message = `Link copied to clipboard: ${shareUrl}`;
// alert(message);
pushLog(message);
} else {
console.log('error', error);
const message = `Error: ${error.message}`;
// alert(message);
pushLog(message);
}
}}
>
📣 share{lastShared && lastShared === (activeCode || code) ? 'd!' : ''}
</button>
)}
{isEmbedded && (
<button className={cx('hover:bg-gray-300 px-2')}>
<a href={window.location.href} target="_blank" rel="noopener noreferrer" title="Open in REPL">
🚀 open
</a>
</button>
)}
{isEmbedded && (
<button className={cx('hover:bg-gray-300 px-2')}>
<a
onClick={() => {
window.location.href = initialUrl;
window.location.reload();
}}
title="Reset"
>
💔 reset
</a>
</button>
)}
</div>
</header>
)}
<section className="grow flex flex-col text-gray-100">
<div className="grow relative flex overflow-auto" id="code">
{/* onCursor={markParens} */}
+50 -1
View File
@@ -51,7 +51,56 @@ Pattern.prototype.piano = function () {
.s('piano')
.fmap((value) => {
// pan by pitch
const pan = panwidth(Math.min(toMidi(value.note) / maxPan, 1), 0.5);
const pan = panwidth(Math.min(toMidi(value.note || value.n) / maxPan, 1), 0.5);
return { ...value, pan: (value.pan || 1) * pan };
});
};
samples({
jazzbass: {
_base: './samples/jazzbass/moog_',
c2: 'c2.mp3',
e2: 'e2.mp3',
a2: 'a2.mp3',
c3: 'c3.mp3',
e3: 'e3.mp3',
a3: 'a3.mp3',
c4: 'c4.mp3',
},
stage73: {
_base: './samples/stage73/',
c2: ['quiet/c2.mp3', 'loud/c2.mp3'],
e2: ['quiet/e2.mp3', 'loud/e2.mp3'],
a2: ['quiet/a2.mp3', 'loud/a2.mp3'],
c3: ['quiet/c3.mp3', 'loud/c3.mp3'],
e3: ['quiet/e3.mp3', 'loud/e3.mp3'],
a3: ['quiet/a3.mp3', 'loud/a3.mp3'],
c4: ['quiet/c4.mp3', 'loud/c4.mp3'],
e4: ['quiet/e4.mp3', 'loud/e4.mp3'],
a4: ['quiet/a4.mp3', 'loud/a4.mp3'],
c5: ['quiet/c5.mp3', 'loud/c5.mp3'],
e5: ['quiet/e5.mp3', 'loud/e5.mp3'],
a5: ['quiet/a5.mp3', 'loud/a5.mp3'],
c6: ['quiet/c6.mp3', 'loud/c6.mp3'],
},
flute: {
_base: './samples/flute/',
g2: 'g2.mp3',
c3: 'c3.mp3',
f3: 'f3.mp3',
c4: 'c4.mp3',
f4: 'f4.mp3',
c5: 'c5.mp3',
},
});
samples(
{
bd: 'bd.mp3',
sd: ['sd.mp3', 'sd2.mp3'],
hh: ['hh.mp3'],
snap: ['snap.mp3'],
oh: ['oh.mp3'],
},
'./samples/president/president_',
);
+109
View File
@@ -1019,3 +1019,112 @@ x=>x.add(7).color('steelblue')
.stack(s("bd:1*2,~ sd:0,[~ hh:0]*2"))
.out()
.pianoroll({vertical:1})`;
export const root73 = `const root = 'E'
stack(
stack(
s("<bd(5,12) bd(3,12)>"),
s("hh!6").echo(2,1/12+.02,.2), // .begin(0.04),
s("~!5 oh"), // hush(),
s("~ <sd!7 [sd@3 sd@2 sd]>")
).slow(1) //.hcutoff(2000)
,
"<0(3,9) [2 <-3 3>]>"
.scale(root+'2 minor')
.legato(1).note().fast(2).s('jazzbass'),
"0 2 4 1".euclid(7,12)
.off(1/16, x=>x.add(2).color('steelblue'))
.off(1/12, x=>x.add(7).color('orange'))
.degradeBy(0.3)
.slow(4)
.scale(root+'4 minor').note()
.gain(.9)
.s('stage73').n(rand.range(0,.7).round())
.legato(perlin.range(.1,.5))
.velocity(perlin.range(.5,.8))
.echo(4, 1/6, .5), //.hcutoff(1000).hresonance(10),
mini(root+'m7@5 <Ab7 Eb7>').slow(2).voicings().transpose(0)
//.euclid(5,12,1)
.euclidLegato(5,12,1)
.note()
.gain(0.5)
.echo(1, 1/12, .5)
.slow(1)
.s('stage73')
.legato(.1)
.color('tomato')
.cutoff("300@2 600".fast(2))
//.resonance("10 20 25 10")
.n(1)
).slow(4/2).clip(1)
.out()
.pianoroll({autorange:0,vertical:1})
// strudel disable-highlighting`;
export const flute73 = `
const harmony = x=>x.scale(cat('E major','F# minor').slow(4)).note().clip(1)
stack(
// flute
"<0 2 5 4>"
.off(1/6, add(2))
.off(1/12, add(5))
.layer(harmony)
.legato("<1 .1>/16")
.echo("<1 3>/16",1/3,.5)
.s('flute')
.cutoff(perlin.range(500,2000))
.color('darkseagreen')
,
// bass
"<-7 -5 -9 -5>(3,9)"
.legato("<2.5 1.5>/16")
.layer(harmony)
.gain("1 .8 1")
.s('stage73')
.color('brown'),
// drums
s("bd*3, [~@2 <hh!3 hh*3>]*2,~ snap".slow(2)).gain(.4)
)
//.hcutoff(800)
.out()
.pianoroll({vertical:1,autorange:0})
`;
export const frequencyTest = `sequence(880, [440, 660], 440, 660)
.div(slowcat(3,2).slow(2))
.off(1/8,mul(2))
.off(1/4,mul(3))
.freq()
.legato(2)
.slow(2)
.s('sawtooth').cutoff(1000)
.out()
`;
export const gameboyParty = `
stack(
freq(
sequence(1,2).mul(55/2) // frequencies
.mul(slowcat(1,2))
.mul(slowcat(1,3/2,4/3,5/3).slow(8))
.fast(3)
.velocity(.5)
)
.s(cat('sawtooth','square').fast(2))
.attack(.01).decay(.02).sustain(.5).release(.1)
.cutoff(2000) //.resonance(25)
,
freq(
sequence(1,[3/2,4/3],5/3)
.off(1/6, x=>x.mul(2).velocity(.5))
.iter(3)
.fast(1)
.mul(220)
)
.gain(.5)
.s(cat('sawtooth','square').slow(8))
.legato(sine.slow(16).add(.5).div(2))
.echo(2,1/12,.6)
.attack(.01).decay(.02).sustain(.5).release(.1)
)
.out()`;