mirror of
https://codeberg.org/uzu/strudel
synced 2026-09-27 23:15:12 -04:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2bc208d8f5 |
@@ -1865,12 +1865,12 @@ export const { nudge } = registerControl('nudge');
|
|||||||
* Sets the default octave of a synth.
|
* Sets the default octave of a synth.
|
||||||
*
|
*
|
||||||
* @name octave
|
* @name octave
|
||||||
* @synonyms oct
|
|
||||||
* @param {number | Pattern} octave octave number
|
* @param {number | Pattern} octave octave number
|
||||||
* @example
|
* @example
|
||||||
* n("0,4,7").scale("F:minor").s('supersaw').octave("<0 1 2 3>")
|
* n("0,4,7").s('supersquare').octave("<3 4 5 6>").osc()
|
||||||
|
* @superDirtOnly
|
||||||
*/
|
*/
|
||||||
export const { octave, oct } = registerControl('octave', 'oct');
|
export const { octave } = registerControl('octave');
|
||||||
|
|
||||||
// ['ophatdecay'],
|
// ['ophatdecay'],
|
||||||
// TODO: example
|
// TODO: example
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import {
|
|||||||
stringifyValues,
|
stringifyValues,
|
||||||
} from './util.mjs';
|
} from './util.mjs';
|
||||||
import drawLine from './drawLine.mjs';
|
import drawLine from './drawLine.mjs';
|
||||||
import { logger } from './logger.mjs';
|
import { errorLogger, logger } from './logger.mjs';
|
||||||
|
|
||||||
let stringParser;
|
let stringParser;
|
||||||
|
|
||||||
@@ -414,7 +414,7 @@ export class Pattern {
|
|||||||
try {
|
try {
|
||||||
return this.query(new State(new TimeSpan(begin, end), controls));
|
return this.query(new State(new TimeSpan(begin, end), controls));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger(`[query]: ${err.message}`, 'error');
|
errorLogger(err, 'query');
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import readline from 'readline';
|
|||||||
import os from 'os';
|
import os from 'os';
|
||||||
|
|
||||||
const LOG = !!process.env.LOG || false;
|
const LOG = !!process.env.LOG || false;
|
||||||
const PORT = process.env.PORT || 5432;
|
|
||||||
const VALID_AUDIO_EXTENSIONS = ['wav', 'mp3', 'ogg'];
|
const VALID_AUDIO_EXTENSIONS = ['wav', 'mp3', 'ogg'];
|
||||||
|
|
||||||
const isAudioFile = (f) => {
|
const isAudioFile = (f) => {
|
||||||
@@ -55,6 +54,7 @@ async function getBanks(directory, flat = false) {
|
|||||||
banks[bank].push(subDir);
|
banks[bank].push(subDir);
|
||||||
return subDir;
|
return subDir;
|
||||||
});
|
});
|
||||||
|
banks._base = `http://localhost:5432`;
|
||||||
return { banks, files };
|
return { banks, files };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,6 +134,8 @@ const server = http.createServer(async (req, res) => {
|
|||||||
readStream.pipe(res);
|
readStream.pipe(res);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
const PORT = process.env.PORT || 5432;
|
||||||
const IP_ADDRESS = '0.0.0.0';
|
const IP_ADDRESS = '0.0.0.0';
|
||||||
let IP;
|
let IP;
|
||||||
const networkInterfaces = os.networkInterfaces();
|
const networkInterfaces = os.networkInterfaces();
|
||||||
|
|||||||
@@ -540,7 +540,7 @@ export const getDistortion = (distort, postgain, algorithm) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getFrequencyFromValue = (value, defaultNote = 36) => {
|
export const getFrequencyFromValue = (value, defaultNote = 36) => {
|
||||||
let { note, freq, octave = 0 } = value;
|
let { note, freq } = value;
|
||||||
note = note || defaultNote;
|
note = note || defaultNote;
|
||||||
if (typeof note === 'string') {
|
if (typeof note === 'string') {
|
||||||
note = noteToMidi(note); // e.g. c3 => 48
|
note = noteToMidi(note); // e.g. c3 => 48
|
||||||
@@ -549,7 +549,7 @@ export const getFrequencyFromValue = (value, defaultNote = 36) => {
|
|||||||
if (!freq && typeof note === 'number') {
|
if (!freq && typeof note === 'number') {
|
||||||
freq = midiToFreq(note); // + 48);
|
freq = midiToFreq(note); // + 48);
|
||||||
}
|
}
|
||||||
freq *= Math.pow(2, octave);
|
|
||||||
return Number(freq);
|
return Number(freq);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { getBaseURL, getCommonSampleInfo } from './util.mjs';
|
import { getCommonSampleInfo } from './util.mjs';
|
||||||
import { registerSound, registerWaveTable } from './index.mjs';
|
import { registerSound, registerWaveTable } from './index.mjs';
|
||||||
import { getAudioContext } from './audioContext.mjs';
|
import { getAudioContext } from './audioContext.mjs';
|
||||||
import { getADSRValues, getParamADSR, getPitchEnvelope, getVibratoOscillator } from './helpers.mjs';
|
import { getADSRValues, getParamADSR, getPitchEnvelope, getVibratoOscillator } from './helpers.mjs';
|
||||||
@@ -211,7 +211,7 @@ export async function fetchSampleMap(url) {
|
|||||||
// not a browser
|
// not a browser
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const base = getBaseURL(url);
|
const base = url.split('/').slice(0, -1).join('/');
|
||||||
if (typeof fetch === 'undefined') {
|
if (typeof fetch === 'undefined') {
|
||||||
// skip fetch when in node / testing
|
// skip fetch when in node / testing
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -668,7 +668,6 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
|||||||
curve: 1.5,
|
curve: 1.5,
|
||||||
});
|
});
|
||||||
lfo.connect(amGain.gain);
|
lfo.connect(amGain.gain);
|
||||||
audioNodes.push(lfo);
|
|
||||||
chain.push(amGain);
|
chain.push(amGain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export class Orbit {
|
|||||||
return effectSend(node, this.delayNode, amount);
|
return effectSend(node, this.delayNode, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
duck(t, onsettime = 0, attacktime = 0.16, depth = 0.8) {
|
duck(t, onsettime = 0, attacktime = 0.1, depth = 1) {
|
||||||
const onset = onsettime;
|
const onset = onsettime;
|
||||||
const attack = Math.max(attacktime, 0.002);
|
const attack = Math.max(attacktime, 0.002);
|
||||||
const gainParam = this.output.gain;
|
const gainParam = this.output.gain;
|
||||||
@@ -178,7 +178,7 @@ export class SuperdoughAudioController {
|
|||||||
this.output.reset();
|
this.output.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
duck(targetOrbits, t, onsettime = 0, attacktime = 0.16, depth = 0.8) {
|
duck(targetOrbits, t, onsettime = 0, attacktime = 0.1, depth = 1) {
|
||||||
const targetArr = [targetOrbits].flat();
|
const targetArr = [targetOrbits].flat();
|
||||||
const onsetArr = [onsettime].flat();
|
const onsetArr = [onsettime].flat();
|
||||||
const attackArr = [attacktime].flat();
|
const attackArr = [attacktime].flat();
|
||||||
|
|||||||
@@ -114,13 +114,3 @@ export function getCommonSampleInfo(hapValue, bank) {
|
|||||||
export const pickAndRename = (source, map) => {
|
export const pickAndRename = (source, map) => {
|
||||||
return Object.fromEntries(Object.entries(map).map(([newKey, oldKey]) => [newKey, source[oldKey]]));
|
return Object.fromEntries(Object.entries(map).map(([newKey, oldKey]) => [newKey, source[oldKey]]));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getBaseURL = (url) => {
|
|
||||||
try {
|
|
||||||
// For real URLs
|
|
||||||
return new URL('.', new URL(url)).href.replace(/\/$/, ''); // removes trailing slash
|
|
||||||
} catch {
|
|
||||||
// For pseudo URLS
|
|
||||||
return url.split('/').slice(0, -1).join('/');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { getAudioContext, registerSound } from './index.mjs';
|
import { getAudioContext, registerSound } from './index.mjs';
|
||||||
import { getBaseURL, getCommonSampleInfo } from './util.mjs';
|
import { getCommonSampleInfo } from './util.mjs';
|
||||||
import {
|
import {
|
||||||
applyFM,
|
applyFM,
|
||||||
applyParameterModulators,
|
applyParameterModulators,
|
||||||
@@ -190,7 +190,6 @@ export const tables = async (url, frameLen, json, options = {}) => {
|
|||||||
if (url.startsWith('local:')) {
|
if (url.startsWith('local:')) {
|
||||||
url = `http://localhost:5432`;
|
url = `http://localhost:5432`;
|
||||||
}
|
}
|
||||||
const base = getBaseURL(url);
|
|
||||||
if (typeof fetch !== 'function') {
|
if (typeof fetch !== 'function') {
|
||||||
// not a browser
|
// not a browser
|
||||||
return;
|
return;
|
||||||
@@ -201,7 +200,7 @@ export const tables = async (url, frameLen, json, options = {}) => {
|
|||||||
}
|
}
|
||||||
return fetch(url)
|
return fetch(url)
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((json) => _processTables(json, base, frameLen, options))
|
.then((json) => _processTables(json, url, frameLen, options))
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw new Error(`error loading "${url}"`);
|
throw new Error(`error loading "${url}"`);
|
||||||
|
|||||||
@@ -5,7 +5,16 @@ This program is free software: you can redistribute it and/or modify it under th
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Note, Interval, Scale } from '@tonaljs/tonal';
|
import { Note, Interval, Scale } from '@tonaljs/tonal';
|
||||||
import { register, _mod, logger, isNote, noteToMidi, removeUndefineds, getAccidentalsOffset } from '@strudel/core';
|
import {
|
||||||
|
_mod,
|
||||||
|
errorLogger,
|
||||||
|
getAccidentalsOffset,
|
||||||
|
isNote,
|
||||||
|
logger,
|
||||||
|
noteToMidi,
|
||||||
|
register,
|
||||||
|
removeUndefineds,
|
||||||
|
} from '@strudel/core';
|
||||||
import { stepInNamedScale, nearestNumberIndex } from './tonleiter.mjs';
|
import { stepInNamedScale, nearestNumberIndex } from './tonleiter.mjs';
|
||||||
|
|
||||||
const octavesInterval = (octaves) => (octaves <= 0 ? -1 : 1) + octaves * 7 + 'P';
|
const octavesInterval = (octaves) => (octaves <= 0 ? -1 : 1) + octaves * 7 + 'P';
|
||||||
@@ -294,7 +303,7 @@ export const scale = register(
|
|||||||
}
|
}
|
||||||
if (offset != 0) scaleNote = Note.transpose(scaleNote, Interval.fromSemitones(offset));
|
if (offset != 0) scaleNote = Note.transpose(scaleNote, Interval.fromSemitones(offset));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger(`[tonal] ${err.message}`, 'error');
|
errorLogger(err, 'tonal');
|
||||||
return; // will be removed
|
return; // will be removed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7302,18 +7302,18 @@ exports[`runs examples > example "nrpv" example index 0 1`] = `
|
|||||||
|
|
||||||
exports[`runs examples > example "octave" example index 0 1`] = `
|
exports[`runs examples > example "octave" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/1 | note:F3 s:supersaw octave:0 ]",
|
"[ 0/1 → 1/1 | n:0 s:supersquare octave:3 ]",
|
||||||
"[ 0/1 → 1/1 | note:C4 s:supersaw octave:0 ]",
|
"[ 0/1 → 1/1 | n:4 s:supersquare octave:3 ]",
|
||||||
"[ 0/1 → 1/1 | note:F4 s:supersaw octave:0 ]",
|
"[ 0/1 → 1/1 | n:7 s:supersquare octave:3 ]",
|
||||||
"[ 1/1 → 2/1 | note:F3 s:supersaw octave:1 ]",
|
"[ 1/1 → 2/1 | n:0 s:supersquare octave:4 ]",
|
||||||
"[ 1/1 → 2/1 | note:C4 s:supersaw octave:1 ]",
|
"[ 1/1 → 2/1 | n:4 s:supersquare octave:4 ]",
|
||||||
"[ 1/1 → 2/1 | note:F4 s:supersaw octave:1 ]",
|
"[ 1/1 → 2/1 | n:7 s:supersquare octave:4 ]",
|
||||||
"[ 2/1 → 3/1 | note:F3 s:supersaw octave:2 ]",
|
"[ 2/1 → 3/1 | n:0 s:supersquare octave:5 ]",
|
||||||
"[ 2/1 → 3/1 | note:C4 s:supersaw octave:2 ]",
|
"[ 2/1 → 3/1 | n:4 s:supersquare octave:5 ]",
|
||||||
"[ 2/1 → 3/1 | note:F4 s:supersaw octave:2 ]",
|
"[ 2/1 → 3/1 | n:7 s:supersquare octave:5 ]",
|
||||||
"[ 3/1 → 4/1 | note:F3 s:supersaw octave:3 ]",
|
"[ 3/1 → 4/1 | n:0 s:supersquare octave:6 ]",
|
||||||
"[ 3/1 → 4/1 | note:C4 s:supersaw octave:3 ]",
|
"[ 3/1 → 4/1 | n:4 s:supersquare octave:6 ]",
|
||||||
"[ 3/1 → 4/1 | note:F4 s:supersaw octave:3 ]",
|
"[ 3/1 → 4/1 | n:7 s:supersquare octave:6 ]",
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -8,34 +8,3 @@ export function ActionButton({ children, label, labelIsHidden, className, ...but
|
|||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SpecialActionButton(props) {
|
|
||||||
const { className, ...buttonProps } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ActionButton
|
|
||||||
{...buttonProps}
|
|
||||||
className={cx('bg-background p-2 max-w-[300px] rounded-md hover:opacity-50', className)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ActionInput({ label, className, ...props }) {
|
|
||||||
return (
|
|
||||||
<label className={cx('inline-flex items-center cursor-pointer', className)}>
|
|
||||||
<input {...props} className="sr-only peer" />
|
|
||||||
|
|
||||||
<span className="inline-flex items-center peer-hover:opacity-50">{label}</span>
|
|
||||||
</label>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SpecialActionInput({ className, ...props }) {
|
|
||||||
return (
|
|
||||||
<ActionInput
|
|
||||||
{...props}
|
|
||||||
className={className}
|
|
||||||
label={<span className="bg-background p-2 max-w-[300px] rounded-md">{props.label}</span>}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
import { errorLogger } from '@strudel/core';
|
|
||||||
import { useSettings, storePrebakeScript } from '../../../settings.mjs';
|
|
||||||
import { SpecialActionInput } from '../button/action-button';
|
|
||||||
|
|
||||||
async function importScript(script) {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.readAsText(script);
|
|
||||||
|
|
||||||
reader.onload = () => {
|
|
||||||
const text = reader.result;
|
|
||||||
storePrebakeScript(text);
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.onerror = () => {
|
|
||||||
errorLogger(new Error('failed to import prebake script'), 'importScript');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export function ImportPrebakeScriptButton() {
|
|
||||||
const settings = useSettings();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SpecialActionInput
|
|
||||||
type="file"
|
|
||||||
label="import prebake script"
|
|
||||||
accept=".strudel"
|
|
||||||
onChange={(e) => importScript(e.target.files[0])}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -7,8 +7,6 @@ import { AudioDeviceSelector } from './AudioDeviceSelector.jsx';
|
|||||||
import { AudioEngineTargetSelector } from './AudioEngineTargetSelector.jsx';
|
import { AudioEngineTargetSelector } from './AudioEngineTargetSelector.jsx';
|
||||||
import { confirmDialog } from '../../util.mjs';
|
import { confirmDialog } from '../../util.mjs';
|
||||||
import { DEFAULT_MAX_POLYPHONY, setMaxPolyphony, setMultiChannelOrbits } from '@strudel/webaudio';
|
import { DEFAULT_MAX_POLYPHONY, setMaxPolyphony, setMultiChannelOrbits } from '@strudel/webaudio';
|
||||||
import { ActionButton, SpecialActionButton } from '../button/action-button.jsx';
|
|
||||||
import { ImportPrebakeScriptButton } from './ImportPrebakeScriptButton.jsx';
|
|
||||||
|
|
||||||
function Checkbox({ label, value, onChange, disabled = false }) {
|
function Checkbox({ label, value, onChange, disabled = false }) {
|
||||||
return (
|
return (
|
||||||
@@ -115,7 +113,6 @@ export function SettingsTab({ started }) {
|
|||||||
isTabIndentationEnabled,
|
isTabIndentationEnabled,
|
||||||
isMultiCursorEnabled,
|
isMultiCursorEnabled,
|
||||||
patternAutoStart,
|
patternAutoStart,
|
||||||
includePrebakeScriptInShare,
|
|
||||||
} = useSettings();
|
} = useSettings();
|
||||||
const shouldAlwaysSync = isUdels();
|
const shouldAlwaysSync = isUdels();
|
||||||
const canChangeAudioDevice = AudioContext.prototype.setSinkId != null;
|
const canChangeAudioDevice = AudioContext.prototype.setSinkId != null;
|
||||||
@@ -207,15 +204,6 @@ export function SettingsTab({ started }) {
|
|||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</div>
|
</div>
|
||||||
<FormItem label="Prebake">
|
|
||||||
<ImportPrebakeScriptButton />
|
|
||||||
<Checkbox
|
|
||||||
label="Include prebake script in share"
|
|
||||||
onChange={(cbEvent) => settingsMap.setKey('includePrebakeScriptInShare', cbEvent.target.checked)}
|
|
||||||
value={includePrebakeScriptInShare}
|
|
||||||
/>
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem label="Keybindings">
|
<FormItem label="Keybindings">
|
||||||
<ButtonGroup
|
<ButtonGroup
|
||||||
value={keybindings}
|
value={keybindings}
|
||||||
@@ -325,7 +313,8 @@ export function SettingsTab({ started }) {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="Zen Mode">Try clicking the logo in the top left!</FormItem>
|
<FormItem label="Zen Mode">Try clicking the logo in the top left!</FormItem>
|
||||||
<FormItem label="Reset Settings">
|
<FormItem label="Reset Settings">
|
||||||
<SpecialActionButton
|
<button
|
||||||
|
className="bg-background p-2 max-w-[300px] rounded-md hover:opacity-50"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
confirmDialog('Sure?').then((r) => {
|
confirmDialog('Sure?').then((r) => {
|
||||||
if (r) {
|
if (r) {
|
||||||
@@ -336,7 +325,7 @@ export function SettingsTab({ started }) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
restore default settings
|
restore default settings
|
||||||
</SpecialActionButton>
|
</button>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ import { aliasBank, registerSynthSounds, registerZZFXSounds, samples } from '@st
|
|||||||
import { registerSamplesFromDB } from './idbutils.mjs';
|
import { registerSamplesFromDB } from './idbutils.mjs';
|
||||||
import './piano.mjs';
|
import './piano.mjs';
|
||||||
import './files.mjs';
|
import './files.mjs';
|
||||||
import { settingsMap } from '@src/settings.mjs';
|
|
||||||
import { evaluate } from '@strudel/transpiler';
|
|
||||||
|
|
||||||
const { BASE_URL } = import.meta.env;
|
const { BASE_URL } = import.meta.env;
|
||||||
const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL;
|
const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ This program is free software: you can redistribute it and/or modify it under th
|
|||||||
|
|
||||||
import { code2hash, getPerformanceTimeSeconds, logger, silence } from '@strudel/core';
|
import { code2hash, getPerformanceTimeSeconds, logger, silence } from '@strudel/core';
|
||||||
import { getDrawContext } from '@strudel/draw';
|
import { getDrawContext } from '@strudel/draw';
|
||||||
import { evaluate, transpiler } from '@strudel/transpiler';
|
import { transpiler } from '@strudel/transpiler';
|
||||||
import {
|
import {
|
||||||
getAudioContextCurrentTime,
|
getAudioContextCurrentTime,
|
||||||
webaudioOutput,
|
webaudioOutput,
|
||||||
@@ -63,10 +63,11 @@ async function getModule(name) {
|
|||||||
const initialCode = `// LOADING`;
|
const initialCode = `// LOADING`;
|
||||||
|
|
||||||
export function useReplContext() {
|
export function useReplContext() {
|
||||||
const { isSyncEnabled, audioEngineTarget, prebakeScript, includePrebakeScriptInShare } = useSettings();
|
const { isSyncEnabled, audioEngineTarget } = useSettings();
|
||||||
const shouldUseWebaudio = audioEngineTarget !== audioEngineTargets.osc;
|
const shouldUseWebaudio = audioEngineTarget !== audioEngineTargets.osc;
|
||||||
const defaultOutput = shouldUseWebaudio ? webaudioOutput : superdirtOutput;
|
const defaultOutput = shouldUseWebaudio ? webaudioOutput : superdirtOutput;
|
||||||
const getTime = shouldUseWebaudio ? getAudioContextCurrentTime : getPerformanceTimeSeconds;
|
const getTime = shouldUseWebaudio ? getAudioContextCurrentTime : getPerformanceTimeSeconds;
|
||||||
|
|
||||||
const init = useCallback(() => {
|
const init = useCallback(() => {
|
||||||
const drawTime = [-2, 2];
|
const drawTime = [-2, 2];
|
||||||
const drawContext = getDrawContext();
|
const drawContext = getDrawContext();
|
||||||
@@ -83,12 +84,7 @@ export function useReplContext() {
|
|||||||
pattern: silence,
|
pattern: silence,
|
||||||
drawTime,
|
drawTime,
|
||||||
drawContext,
|
drawContext,
|
||||||
prebake: async () =>
|
prebake: async () => Promise.all([modulesLoading, presets]),
|
||||||
Promise.all([modulesLoading, presets]).then(() => {
|
|
||||||
if (prebakeScript?.length) {
|
|
||||||
return evaluate(prebakeScript ?? '');
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
onUpdateState: (state) => {
|
onUpdateState: (state) => {
|
||||||
setReplState({ ...state });
|
setReplState({ ...state });
|
||||||
},
|
},
|
||||||
@@ -218,13 +214,7 @@ export function useReplContext() {
|
|||||||
editorRef.current.repl.evaluate(code);
|
editorRef.current.repl.evaluate(code);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleShare = async () => {
|
const handleShare = async () => shareCode(replState.code);
|
||||||
let code = replState.code;
|
|
||||||
if (includePrebakeScriptInShare) {
|
|
||||||
code = prebakeScript + '\n' + code;
|
|
||||||
}
|
|
||||||
shareCode(code);
|
|
||||||
};
|
|
||||||
const context = {
|
const context = {
|
||||||
started,
|
started,
|
||||||
pending,
|
pending,
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { code2hash, evalScope, hash2code, logger } from '@strudel/core';
|
import { evalScope, hash2code, logger } from '@strudel/core';
|
||||||
import { settingPatterns } from '../settings.mjs';
|
import { settingPatterns } from '../settings.mjs';
|
||||||
import { setVersionDefaults } from '@strudel/webaudio';
|
import { setVersionDefaults } from '@strudel/webaudio';
|
||||||
import { getMetadata } from '../metadata_parser';
|
import { getMetadata } from '../metadata_parser';
|
||||||
import { isTauri } from '../tauri.mjs';
|
import { isTauri } from '../tauri.mjs';
|
||||||
import './Repl.css';
|
import './Repl.css';
|
||||||
import { createClient } from '@supabase/supabase-js';
|
import { createClient } from '@supabase/supabase-js';
|
||||||
|
import { nanoid } from 'nanoid';
|
||||||
import { writeText } from '@tauri-apps/plugin-clipboard-manager';
|
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';
|
||||||
|
|
||||||
@@ -108,8 +109,9 @@ export function confirmDialog(msg) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let lastShared;
|
||||||
|
|
||||||
//RIP due to SPAM
|
//RIP due to SPAM
|
||||||
// let lastShared;
|
|
||||||
// export async function shareCode(codeToShare) {
|
// export async function shareCode(codeToShare) {
|
||||||
// // const codeToShare = activeCode || code;
|
// // const codeToShare = activeCode || code;
|
||||||
// if (lastShared === codeToShare) {
|
// if (lastShared === codeToShare) {
|
||||||
@@ -144,10 +146,9 @@ export function confirmDialog(msg) {
|
|||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
|
|
||||||
export async function shareCode(codeToShare) {
|
export async function shareCode() {
|
||||||
try {
|
try {
|
||||||
const hash = '#' + code2hash(codeToShare);
|
const shareUrl = window.location.href;
|
||||||
const shareUrl = window.location.origin + window.location.pathname + hash;
|
|
||||||
if (isTauri()) {
|
if (isTauri()) {
|
||||||
await writeText(shareUrl);
|
await writeText(shareUrl);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -45,13 +45,11 @@ export const defaultSettings = {
|
|||||||
isPanelOpen: true,
|
isPanelOpen: true,
|
||||||
togglePanelTrigger: 'click', //click | hover
|
togglePanelTrigger: 'click', //click | hover
|
||||||
userPatterns: '{}',
|
userPatterns: '{}',
|
||||||
prebakeScript: '',
|
|
||||||
audioEngineTarget: audioEngineTargets.webaudio,
|
audioEngineTarget: audioEngineTargets.webaudio,
|
||||||
isButtonRowHidden: false,
|
isButtonRowHidden: false,
|
||||||
isCSSAnimationDisabled: false,
|
isCSSAnimationDisabled: false,
|
||||||
maxPolyphony: 128,
|
maxPolyphony: 128,
|
||||||
multiChannelOrbits: false,
|
multiChannelOrbits: false,
|
||||||
includePrebakeScriptInShare: true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let search = null;
|
let search = null;
|
||||||
@@ -98,7 +96,6 @@ export function useSettings() {
|
|||||||
isPanelOpen: parseBoolean(state.isPanelOpen),
|
isPanelOpen: parseBoolean(state.isPanelOpen),
|
||||||
userPatterns: userPatterns,
|
userPatterns: userPatterns,
|
||||||
multiChannelOrbits: parseBoolean(state.multiChannelOrbits),
|
multiChannelOrbits: parseBoolean(state.multiChannelOrbits),
|
||||||
includePrebakeScriptInShare: parseBoolean(state.includePrebakeScriptInShare),
|
|
||||||
patternAutoStart: isUdels()
|
patternAutoStart: isUdels()
|
||||||
? false
|
? false
|
||||||
: state.patternAutoStart === undefined
|
: state.patternAutoStart === undefined
|
||||||
@@ -111,8 +108,6 @@ export const setActiveFooter = (tab) => settingsMap.setKey('activeFooter', tab);
|
|||||||
export const setPanelPinned = (bool) => settingsMap.setKey('isPanelPinned', bool);
|
export const setPanelPinned = (bool) => settingsMap.setKey('isPanelPinned', bool);
|
||||||
export const setIsPanelOpened = (bool) => settingsMap.setKey('isPanelOpen', bool);
|
export const setIsPanelOpened = (bool) => settingsMap.setKey('isPanelOpen', bool);
|
||||||
|
|
||||||
export const storePrebakeScript = (script) => settingsMap.setKey('prebakeScript', script);
|
|
||||||
|
|
||||||
export const setIsZen = (active) => settingsMap.setKey('isZen', !!active);
|
export const setIsZen = (active) => settingsMap.setKey('isZen', !!active);
|
||||||
|
|
||||||
const patternSetting = (key) =>
|
const patternSetting = (key) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user