diff --git a/src/as/dsp/build.ts b/src/as/dsp/build.ts index a9f4cf1..ce55424 100644 --- a/src/as/dsp/build.ts +++ b/src/as/dsp/build.ts @@ -376,9 +376,24 @@ export function TrackBuild(track: Track) { setupVm.CreateValues(context.values) setupVm.End() - let L = program.scope.vars['L'] - let R = program.scope.vars['R'] - let LR = program.scope.vars['LR'] + let L: AstNode | undefined = program.scope.vars['L'] + let R: AstNode | undefined = program.scope.vars['R'] + let LR: AstNode | undefined = program.scope.vars['LR'] + + // @ts-ignore + if (L?.value?.kind !== ValueBase.Kind.Audio && L?.value?.kind !== ValueBase.Kind.Dynamic) { + L = undefined + } + + // @ts-ignore + if (R?.value?.kind !== ValueBase.Kind.Audio && R?.value?.kind !== ValueBase.Kind.Dynamic) { + R = undefined + } + + // @ts-ignore + if (LR?.value?.kind !== ValueBase.Kind.Audio && LR?.value?.kind !== ValueBase.Kind.Dynamic) { + LR = undefined + } const slice = program.scope.stack.slice(-2) if (slice.length === 2) { @@ -389,6 +404,33 @@ export function TrackBuild(track: Track) { LR ??= slice.pop()! } + // @ts-ignore + if (L?.value?.kind !== ValueBase.Kind.Audio && L?.value?.kind !== ValueBase.Kind.Dynamic) { + L = undefined + } + + // @ts-ignore + if (R?.value?.kind !== ValueBase.Kind.Audio && R?.value?.kind !== ValueBase.Kind.Dynamic) { + R = undefined + } + + // @ts-ignore + if (LR?.value?.kind !== ValueBase.Kind.Audio && LR?.value?.kind !== ValueBase.Kind.Dynamic) { + LR = undefined + } + + if (!LR) { + if (L && R) { } + else if (L) { + LR = L + L = undefined + } + else if (R) { + LR = R + R = undefined + } + } + const out = { L: L?.value as Value.Audio | undefined, R: R?.value as Value.Audio | undefined, diff --git a/src/comp/DspEditorUi.tsx b/src/comp/DspEditorUi.tsx index 605911b..ec63a47 100644 --- a/src/comp/DspEditorUi.tsx +++ b/src/comp/DspEditorUi.tsx @@ -2,13 +2,11 @@ import { BUFFER_SIZE, createDspNode, PreviewService, SoundValue } from 'dsp' import type { Pane } from 'editor' import { Gfx, Matrix, Rect, wasm as wasmGfx } from 'gfx' import type { Token } from 'lang' -import { $, dispose, Sigui } from 'sigui' +import { Sigui } from 'sigui' import { Canvas } from 'ui' import { assign, dom, Lru, throttle } from 'utils' -import { cn } from '~/lib/cn.ts' import { DspEditor } from '~/src/comp/DspEditor.tsx' import { screen } from '~/src/screen.ts' -import { state } from '~/src/state.ts' import { ListMarkWidget, RmsDecoWidget, WaveGlDecoWidget } from '~/src/ui/editor/widgets/index.ts' import { copyRingInto } from '~/src/util/copy-ring-into.ts' @@ -364,7 +362,7 @@ export function DspEditorUi() { info.el =
- {() => info.didBuildPane &&
+ {() => info.didBuildPane &&
{dspEditor} {canvas}
} diff --git a/src/comp/Help.tsx b/src/comp/Help.tsx new file mode 100644 index 0000000..57ed217 --- /dev/null +++ b/src/comp/Help.tsx @@ -0,0 +1,68 @@ +import { getAllProps, getAllPropsDetailed, getAllPropsReverse } from 'dsp' +import { H3 } from 'ui' +import { keys } from 'utils' +import { dspGens } from '~/generated/typescript/dsp-gens.ts' + +const HIDDEN_PROPS = new Set([ + 'gain', +]) +const AUDIO_PROPS = new Set([ + 'in', + 'sidechain', +]) +const STACK_PROPS = new Set([ + 'in', +]) +const HIDDEN_GENS = new Set([ + 'gen', + 'osc', + 'biquad', + 'moog', + 'svf', + 'dcc', + 'dcfix', +]) + +const OPERATORS = { + '=': { name: 'assign', kind: 'binary' }, + '?': { name: 'pick', kind: 'binary' }, + '+': { name: 'add', kind: 'binary' }, + '-': { name: 'subtract', kind: 'binary' }, + '*': { name: 'multiply', kind: 'binary' }, + '/': { name: 'divide', kind: 'binary' }, + '%': { name: 'modulo', kind: 'binary' }, + '^': { name: 'power', kind: 'binary' }, +} + +export function Help() { + return
+
+

Gens

+
+ {keys(dspGens).filter(name => !HIDDEN_GENS.has(name)).map(name => { + const props = getAllProps(name) + return
+ {name} +
+ {props.filter(name => !HIDDEN_PROPS.has(name)).map(name => + {name} + )} +
+
+ })} +
+
+
+

Ops

+
+ {keys(OPERATORS).map(id => { + const { name, kind } = OPERATORS[id] + return
+ {id} + {name} +
+ })} +
+
+
+} diff --git a/src/comp/HelpModal.tsx b/src/comp/HelpModal.tsx new file mode 100644 index 0000000..ffb03ab --- /dev/null +++ b/src/comp/HelpModal.tsx @@ -0,0 +1,27 @@ +import { $ } from 'sigui' +import { Help } from '~/src/comp/Help.tsx' +import { state } from '~/src/state.ts' + +export function showHelpModal() { + state.modalIsCancelled = false + + const off = $.fx(() => { + const { modalIsCancelled } = state + if (modalIsCancelled) { + off() + return + } + const { user } = state + $() + if (user == null) { + state.modal = + state.modalIsOpen = true + state.modalIsCancelled = false + } + else { + state.modal = null + state.modalIsOpen = false + queueMicrotask(() => off()) + } + }) +} diff --git a/src/lang/interpreter.ts b/src/lang/interpreter.ts index d7d8674..d794b31 100644 --- a/src/lang/interpreter.ts +++ b/src/lang/interpreter.ts @@ -1,7 +1,7 @@ import { dspGens } from '~/generated/typescript/dsp-gens.ts' import type { DspApi } from '~/src/as/dsp/build' import { getAllPropsReverse } from '~/src/as/dsp/util.ts' -import type { Value } from '~/src/as/dsp/value.ts' +import { Value } from '~/src/as/dsp/value.ts' import { Token } from '~/src/lang/tokenize.ts' import { parseNumber, type NumberFormat, type NumberInfo } from '~/src/lang/util.ts' @@ -343,7 +343,9 @@ export function interpret(g: DspApi, data: Record, tokens: Token[]) if (r == null) return while (scope.stack.length) { l = scope.stack.pop() as AstNode & { value: Value } + // if (l.value.kind === Value.Kind.Audio) { r = g.math.add(l.value, r) + // } } const node = new AstNode(AstNode.Type.Result, { value: r }, [t]) return node diff --git a/src/pages/App.tsx b/src/pages/App.tsx index 58fefbd..caab324 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -1,4 +1,4 @@ -import { AudioWaveform, Plus, UserCircle, UserCircle2, X } from 'lucide' +import { AudioWaveform, HelpCircle, LogIn, Plus, UserCircle, UserCircle2, X } from 'lucide' import { Sigui } from 'sigui' import { Button, DropDown } from 'ui' import { dom } from 'utils' @@ -6,7 +6,9 @@ import type { z } from 'zod' import type { Profiles } from '~/api/models.ts' import { cn } from '~/lib/cn.ts' import { icon } from '~/lib/icon.ts' +import { wrapActionAuth } from '~/src/comp/AuthModal.tsx' import { dspEditorUi } from '~/src/comp/DspEditorUi.tsx' +import { showHelpModal } from '~/src/comp/HelpModal.tsx' import { Toast } from '~/src/comp/Toast.tsx' import { ICON_24, ICON_32, ICON_48 } from '~/src/constants.ts' import { CreateProfile } from '~/src/pages/CreateProfile.tsx' @@ -230,8 +232,9 @@ export function App() { const Home = () =>
- {icon(AudioWaveform, ICON_32)} -
ravescript
+ + {icon(AudioWaveform, ICON_32)}
ravescript
+
{() => info.profile ? [ @@ -253,12 +256,21 @@ export function App() {
{() => getDspControls().el}
{() => [ - - {icon(Plus, ICON_32)} New sound + + help + {icon(HelpCircle, { ...ICON_24, class: 'mb-0.5 text-neutral-400' })} + , + + new sound + {icon(Plus, { ...ICON_32, class: 'mb-0.5 text-neutral-400' })} + , + !state.user && { })}> + Login + {icon(LogIn, { ...ICON_24, class: 'mb-0.5 text-neutral-400' })} , ...(() => !state.user ? [] : [ - `/${state.user?.defaultProfile}`}>{() => state.profile?.displayName}, - [ + `/${state.user?.defaultProfile}`}>{() => state.profile?.displayName}, + [ // [Settings, () => { }], [state.user ? Logout :
, () => { }], [New profile, () => { }], @@ -282,7 +294,7 @@ export function App() {
- const Modal = () => state.modalIsOpen &&
+ const AuthModal = () => state.modalIsOpen &&