working
This commit is contained in:
parent
f7f3aa7668
commit
6221099af8
9 changed files with 94 additions and 11 deletions
|
|
@ -147,6 +147,7 @@ export function repl({
|
||||||
|
|
||||||
// set pattern methods that use this repl via closure
|
// set pattern methods that use this repl via closure
|
||||||
const injectPatternMethods = () => {
|
const injectPatternMethods = () => {
|
||||||
|
|
||||||
Pattern.prototype.p = function (id) {
|
Pattern.prototype.p = function (id) {
|
||||||
if (typeof id === 'string' && (id.startsWith('_') || id.endsWith('_'))) {
|
if (typeof id === 'string' && (id.startsWith('_') || id.endsWith('_'))) {
|
||||||
// allows muting a pattern x with x_ or _x
|
// allows muting a pattern x with x_ or _x
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,27 @@ export function ActionButton({ children, label, labelIsHidden, className, ...but
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
export function ActionInput({ label, className, ...inputProps }) {
|
||||||
|
return (
|
||||||
|
<label className={cx("hover:opacity-50 cursor-pointer text-nowrap w-fit", className)}>
|
||||||
|
<input
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
{...inputProps}
|
||||||
|
/>
|
||||||
|
{label}
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 SpecialActionInput(props) {
|
||||||
|
const { className, ...inputProps } = props
|
||||||
|
return <ActionInput {...inputProps} className={cx("bg-background p-2 max-w-[300px] rounded-md hover:opacity-50", className)} />
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { errorLogger } from '@strudel/core';
|
||||||
|
import { useSettings, storeStartupScript } 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;
|
||||||
|
console.info(text)
|
||||||
|
storeStartupScript(text)
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.onerror = () => {
|
||||||
|
errorLogger(new Error('failed to import prebake script'), 'ImportPrebakeScriptButton')
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
export function ImportPrebakeScriptButton() {
|
||||||
|
const settings = useSettings();
|
||||||
|
|
||||||
|
return <SpecialActionInput type="file"
|
||||||
|
label="import prebake script"
|
||||||
|
accept=".strudel, .txt"
|
||||||
|
onChange={(e) => importScript(e.target.files[0])} />
|
||||||
|
|
||||||
|
// return <label className="hover:opacity-50 cursor-pointer">
|
||||||
|
// <input
|
||||||
|
// style={{ display: 'none' }}
|
||||||
|
// type="file"
|
||||||
|
// // multiple
|
||||||
|
// accept=".strudel, .txt"
|
||||||
|
// onChange={(e) => importScript(e.target.files[0])}
|
||||||
|
// />
|
||||||
|
// import prebake script
|
||||||
|
// </label>
|
||||||
|
}
|
||||||
|
|
@ -127,7 +127,7 @@ function PanelContent({ context, tab }) {
|
||||||
case tabNames.reference:
|
case tabNames.reference:
|
||||||
return <Reference />;
|
return <Reference />;
|
||||||
case tabNames.settings:
|
case tabNames.settings:
|
||||||
return <SettingsTab started={context.started} />;
|
return <SettingsTab started={context.started} context={context} />;
|
||||||
case tabNames.files:
|
case tabNames.files:
|
||||||
return <FilesTab />;
|
return <FilesTab />;
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ function UserPatterns({ context }) {
|
||||||
const activePattern = useActivePattern();
|
const activePattern = useActivePattern();
|
||||||
const viewingPatternStore = useViewingPatternData();
|
const viewingPatternStore = useViewingPatternData();
|
||||||
const viewingPatternData = parseJSON(viewingPatternStore);
|
const viewingPatternData = parseJSON(viewingPatternStore);
|
||||||
const { userPatterns, patternFilter, patternAutoStart } = useSettings();
|
const { userPatterns, patternFilter, patternAutoStart, } = useSettings();
|
||||||
const viewingPatternID = viewingPatternData?.id;
|
const viewingPatternID = viewingPatternData?.id;
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-2 flex-grow overflow-hidden h-full pb-2 ">
|
<div className="flex flex-col gap-2 flex-grow overflow-hidden h-full pb-2 ">
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ 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 (
|
||||||
|
|
@ -86,7 +88,7 @@ const fontFamilyOptions = {
|
||||||
|
|
||||||
const RELOAD_MSG = 'Changing this setting requires the window to reload itself. OK?';
|
const RELOAD_MSG = 'Changing this setting requires the window to reload itself. OK?';
|
||||||
|
|
||||||
export function SettingsTab({ started }) {
|
export function SettingsTab({ started,context }) {
|
||||||
const {
|
const {
|
||||||
theme,
|
theme,
|
||||||
keybindings,
|
keybindings,
|
||||||
|
|
@ -113,6 +115,7 @@ export function SettingsTab({ started }) {
|
||||||
isTabIndentationEnabled,
|
isTabIndentationEnabled,
|
||||||
isMultiCursorEnabled,
|
isMultiCursorEnabled,
|
||||||
patternAutoStart,
|
patternAutoStart,
|
||||||
|
startupScript,
|
||||||
} = useSettings();
|
} = useSettings();
|
||||||
const shouldAlwaysSync = isUdels();
|
const shouldAlwaysSync = isUdels();
|
||||||
const canChangeAudioDevice = AudioContext.prototype.setSinkId != null;
|
const canChangeAudioDevice = AudioContext.prototype.setSinkId != null;
|
||||||
|
|
@ -204,6 +207,8 @@ export function SettingsTab({ started }) {
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</div>
|
</div>
|
||||||
|
<ImportPrebakeScriptButton />
|
||||||
|
{/* <SpecialActionButton label="edit startup script" onClick={() => context.editStartupScript(startupScript)}></SpecialActionButton> */}
|
||||||
<FormItem label="Keybindings">
|
<FormItem label="Keybindings">
|
||||||
<ButtonGroup
|
<ButtonGroup
|
||||||
value={keybindings}
|
value={keybindings}
|
||||||
|
|
@ -313,8 +318,7 @@ 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">
|
||||||
<button
|
<SpecialActionButton
|
||||||
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) {
|
||||||
|
|
@ -325,7 +329,7 @@ export function SettingsTab({ started }) {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
restore default settings
|
restore default settings
|
||||||
</button>
|
</SpecialActionButton>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,23 @@
|
||||||
import { Pattern, noteToMidi, valueToMidi } from '@strudel/core';
|
import { Pattern, noteToMidi, valueToMidi } from '@strudel/core';
|
||||||
import { aliasBank, registerSynthSounds, registerZZFXSounds, samples } from '@strudel/webaudio';
|
import { aliasBank, registerSynthSounds, registerZZFXSounds, samples } from '@strudel/webaudio';
|
||||||
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;
|
||||||
const baseCDN = 'https://strudel.b-cdn.net';
|
const baseCDN = 'https://strudel.b-cdn.net';
|
||||||
|
|
||||||
export async function prebake() {
|
export async function prebake() {
|
||||||
|
|
||||||
|
// const settings = settingsMap.get()
|
||||||
|
|
||||||
|
|
||||||
|
// const prebakeScript = settings.startupScript || '';
|
||||||
|
// await evaluate(prebakeScript);
|
||||||
|
|
||||||
// https://archive.org/details/SalamanderGrandPianoV3
|
// https://archive.org/details/SalamanderGrandPianoV3
|
||||||
// License: CC-by http://creativecommons.org/licenses/by/3.0/ Author: Alexander Holm
|
// License: CC-by http://creativecommons.org/licenses/by/3.0/ Author: Alexander Holm
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
|
|
|
||||||
|
|
@ -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 { transpiler } from '@strudel/transpiler';
|
import { evaluate, transpiler } from '@strudel/transpiler';
|
||||||
import {
|
import {
|
||||||
getAudioContextCurrentTime,
|
getAudioContextCurrentTime,
|
||||||
webaudioOutput,
|
webaudioOutput,
|
||||||
|
|
@ -47,6 +47,7 @@ if (typeof window !== 'undefined') {
|
||||||
multiChannelOrbits: parseBoolean(multiChannelOrbits),
|
multiChannelOrbits: parseBoolean(multiChannelOrbits),
|
||||||
});
|
});
|
||||||
modulesLoading = loadModules();
|
modulesLoading = loadModules();
|
||||||
|
// prebakeScript = evaluate(settingsMap.get().startupScript ?? '')
|
||||||
presets = prebake();
|
presets = prebake();
|
||||||
drawContext = getDrawContext();
|
drawContext = getDrawContext();
|
||||||
clearCanvas = () => drawContext.clearRect(0, 0, drawContext.canvas.height, drawContext.canvas.width);
|
clearCanvas = () => drawContext.clearRect(0, 0, drawContext.canvas.height, drawContext.canvas.width);
|
||||||
|
|
@ -63,11 +64,10 @@ async function getModule(name) {
|
||||||
const initialCode = `// LOADING`;
|
const initialCode = `// LOADING`;
|
||||||
|
|
||||||
export function useReplContext() {
|
export function useReplContext() {
|
||||||
const { isSyncEnabled, audioEngineTarget } = useSettings();
|
const { isSyncEnabled, audioEngineTarget, startupScript } = 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();
|
||||||
|
|
@ -84,7 +84,9 @@ export function useReplContext() {
|
||||||
pattern: silence,
|
pattern: silence,
|
||||||
drawTime,
|
drawTime,
|
||||||
drawContext,
|
drawContext,
|
||||||
prebake: async () => Promise.all([modulesLoading, presets]),
|
prebake: async () => Promise.all([modulesLoading, presets,]).then(() => {
|
||||||
|
return evaluate(startupScript ?? '')
|
||||||
|
}),
|
||||||
onUpdateState: (state) => {
|
onUpdateState: (state) => {
|
||||||
setReplState({ ...state });
|
setReplState({ ...state });
|
||||||
},
|
},
|
||||||
|
|
@ -200,6 +202,7 @@ export function useReplContext() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleEvaluate = () => {
|
const handleEvaluate = () => {
|
||||||
editorRef.current.evaluate();
|
editorRef.current.evaluate();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ export const defaultSettings = {
|
||||||
isPanelOpen: true,
|
isPanelOpen: true,
|
||||||
togglePanelTrigger: 'click', //click | hover
|
togglePanelTrigger: 'click', //click | hover
|
||||||
userPatterns: '{}',
|
userPatterns: '{}',
|
||||||
|
startupScript: '//edit this script to run code on startup\n',
|
||||||
audioEngineTarget: audioEngineTargets.webaudio,
|
audioEngineTarget: audioEngineTargets.webaudio,
|
||||||
isButtonRowHidden: false,
|
isButtonRowHidden: false,
|
||||||
isCSSAnimationDisabled: false,
|
isCSSAnimationDisabled: false,
|
||||||
|
|
@ -108,6 +109,8 @@ 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 storeStartupScript = (script) => settingsMap.setKey('startupScript', script);
|
||||||
|
|
||||||
export const setIsZen = (active) => settingsMap.setKey('isZen', !!active);
|
export const setIsZen = (active) => settingsMap.setKey('isZen', !!active);
|
||||||
|
|
||||||
const patternSetting = (key) =>
|
const patternSetting = (key) =>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue