├── .node-version ├── .yarnclean ├── packages ├── automaton-fxs │ ├── README.md │ ├── src │ │ ├── tests │ │ │ ├── utils │ │ │ │ └── jsonCopy.ts │ │ │ ├── add.test.ts │ │ │ └── repeat.test.ts │ │ ├── utils │ │ │ ├── clamp.ts │ │ │ ├── smoothstep.ts │ │ │ ├── smin.ts │ │ │ └── xorshift.ts │ │ ├── add.ts │ │ ├── index.ts │ │ ├── exp.ts │ │ ├── sine.ts │ │ ├── pow.ts │ │ ├── repeat.ts │ │ ├── clamp.ts │ │ ├── hermitePatch.ts │ │ ├── cds.ts │ │ ├── lofi.ts │ │ ├── gravity.ts │ │ └── noise.ts │ ├── tsconfig.json │ ├── jest.config.js │ ├── package.json │ └── rollup.config.js ├── automaton-fxs-v2compat │ ├── README.md │ ├── src │ │ ├── utils │ │ │ ├── clamp.ts │ │ │ ├── smoothstep.ts │ │ │ ├── smin.ts │ │ │ └── xorshift.ts │ │ ├── index.ts │ │ ├── add.ts │ │ ├── exp.ts │ │ ├── sine.ts │ │ ├── pow.ts │ │ ├── clamp.ts │ │ ├── cds.ts │ │ ├── lofi.ts │ │ ├── gravity.ts │ │ └── noise.ts │ ├── tsconfig.json │ ├── package.json │ └── rollup.config.js ├── automaton-with-gui │ ├── src │ │ ├── types │ │ │ ├── WithID.ts │ │ │ ├── WithBypass.ts │ │ │ ├── MinimizeOptions.ts │ │ │ ├── Serializable.ts │ │ │ ├── ToastyParams.ts │ │ │ ├── StateChannelItem.ts │ │ │ ├── SerializableWithID.ts │ │ │ ├── SerializedAutomatonWithGUI.ts │ │ │ ├── GUISettings.ts │ │ │ └── Status.ts │ │ ├── svg.d.ts │ │ ├── view │ │ │ ├── utils │ │ │ │ ├── Resolution.ts │ │ │ │ ├── clipboard.ts │ │ │ │ ├── testRectIntersection.ts │ │ │ │ ├── combineArraysUnique.ts │ │ │ │ ├── useID.ts │ │ │ │ ├── registerMouseNoDragEvent.ts │ │ │ │ ├── useDoubleClick.ts │ │ │ │ ├── useElement.ts │ │ │ │ ├── objectMap.ts │ │ │ │ ├── duplicateName.ts │ │ │ │ ├── useAnimationFrame.ts │ │ │ │ ├── useWheelEvent.ts │ │ │ │ ├── useIntersection.ts │ │ │ │ ├── arraySet.ts │ │ │ │ ├── registerMouseEvent.ts │ │ │ │ ├── binarySearch.ts │ │ │ │ ├── genGrid.ts │ │ │ │ ├── tests │ │ │ │ │ └── genGrid.test.ts │ │ │ │ ├── useRect.ts │ │ │ │ ├── useTimeUnit.ts │ │ │ │ ├── mouseCombo.ts │ │ │ │ └── TimeValueRange.ts │ │ │ ├── icons │ │ │ │ ├── play.svg │ │ │ │ ├── pause.svg │ │ │ │ ├── redo.svg │ │ │ │ ├── undo.svg │ │ │ │ ├── snap.svg │ │ │ │ ├── save.svg │ │ │ │ ├── close.svg │ │ │ │ ├── plus.svg │ │ │ │ ├── beat.svg │ │ │ │ ├── cog.svg │ │ │ │ ├── scale.svg │ │ │ │ ├── curve.svg │ │ │ │ ├── Icons.ts │ │ │ │ ├── retry.svg │ │ │ │ ├── power.svg │ │ │ │ ├── channel.svg │ │ │ │ ├── dope-sheet.svg │ │ │ │ └── automaton-a.svg │ │ │ ├── constants │ │ │ │ ├── Metrics.ts │ │ │ │ └── Colors.ts │ │ │ ├── components │ │ │ │ ├── InspectorHr.tsx │ │ │ │ ├── ContextMenuHr.tsx │ │ │ │ ├── Anchor.tsx │ │ │ │ ├── Labels.tsx │ │ │ │ ├── InspectorHeader.tsx │ │ │ │ ├── StatusIcon.tsx │ │ │ │ ├── InspectorItem.tsx │ │ │ │ ├── Toasty.tsx │ │ │ │ ├── RangeBar.tsx │ │ │ │ ├── RectSelectView.tsx │ │ │ │ ├── DopeSheetUnderlay.tsx │ │ │ │ ├── ContextMenuEntry.tsx │ │ │ │ ├── InspectorLabel.tsx │ │ │ │ ├── AboutLargeA.tsx │ │ │ │ ├── CruveEditorFxBg.tsx │ │ │ │ ├── TimeLoopRegion.tsx │ │ │ │ ├── FxSpawnerEntry.tsx │ │ │ │ ├── InspectorBeat.tsx │ │ │ │ ├── InspectorSnapping.tsx │ │ │ │ ├── ModeSelector.tsx │ │ │ │ ├── TimeValueLines.tsx │ │ │ │ ├── CurveList.tsx │ │ │ │ └── ToastyEntry.tsx │ │ │ ├── states │ │ │ │ ├── Workspace.ts │ │ │ │ ├── Settings.ts │ │ │ │ ├── About.ts │ │ │ │ ├── Header.ts │ │ │ │ ├── FxSpawner.ts │ │ │ │ ├── ContextMenu.ts │ │ │ │ ├── History.ts │ │ │ │ ├── TextPrompt.ts │ │ │ │ └── Toasty.ts │ │ │ └── gui-operation-hooks │ │ │ │ ├── useSelectAllItemsInChannel.ts │ │ │ │ ├── useSelectAll.ts │ │ │ │ └── useSave.ts │ │ ├── utils │ │ │ ├── lofi.ts │ │ │ ├── jsonCopy.ts │ │ │ ├── clamp.ts │ │ │ ├── genID.ts │ │ │ ├── hasOverwrap.ts │ │ │ ├── applyMixins.ts │ │ │ ├── reorderArray.ts │ │ │ ├── tests │ │ │ │ └── reorderArray.test.ts │ │ │ ├── BiMap.ts │ │ │ └── Throttle.ts │ │ ├── ResumeStorage.ts │ │ ├── compat │ │ │ ├── v3types │ │ │ │ ├── V3SerializedChannel.ts │ │ │ │ ├── V3SerializedBezierControlPoint.ts │ │ │ │ ├── V3SerializedCurve.ts │ │ │ │ ├── V3SerializedAutomatonWithGUI.ts │ │ │ │ ├── V3SerializedAutomaton.ts │ │ │ │ ├── V3SerializedBezierNode.ts │ │ │ │ └── V3GUISettings.ts │ │ │ ├── v2types │ │ │ │ ├── V2SerializedParam.ts │ │ │ │ ├── V2AutomatonGUISettings.ts │ │ │ │ ├── V2FxSection.ts │ │ │ │ ├── V2BezierNode.ts │ │ │ │ └── V2SerializedData.ts │ │ │ ├── compat.ts │ │ │ ├── v2Compat.ts │ │ │ └── v3Compat.ts │ │ ├── index.ts │ │ ├── GUIRemocon.ts │ │ ├── ThrottledJSONStorage.ts │ │ └── mixins │ │ │ └── EventEmittable.ts │ ├── readme-images │ │ ├── automaton.png │ │ └── playground.gif │ ├── tsconfig.json │ ├── jest.config.js │ ├── .eslintrc.js │ ├── package.json │ ├── README.md │ └── rollup.config.js └── automaton │ ├── tsconfig.json │ ├── src │ ├── types │ │ ├── FxParam.ts │ │ ├── AutomatonOptions.ts │ │ ├── FxDefinition.ts │ │ ├── SerializedChannel.ts │ │ ├── SerializedCurve.ts │ │ ├── FxSection.ts │ │ ├── SerializedAutomaton.ts │ │ ├── BezierNode.ts │ │ ├── SerializedFxSection.ts │ │ ├── SerializedBezierNode.ts │ │ ├── ChannelUpdateEvent.ts │ │ ├── SerializedChannelItem.ts │ │ └── FxContext.ts │ ├── index.ts │ ├── tests │ │ └── Curve.test.ts │ └── utils │ │ └── binarySearch.ts │ ├── jest.config.js │ ├── package.json │ ├── README.md │ └── rollup.config.js ├── readme-images └── automaton.png ├── .eslintignore ├── .gitignore ├── jest.config.js ├── lerna.json ├── tsconfig.json ├── dev.html ├── .vscode └── launch.json ├── LICENSE ├── package.json ├── README.md └── .github └── workflows └── automaton-fxs-v2compat-inspect.yml /.node-version: -------------------------------------------------------------------------------- 1 | 14.9.0 2 | -------------------------------------------------------------------------------- /.yarnclean: -------------------------------------------------------------------------------- 1 | @types/react-native 2 | -------------------------------------------------------------------------------- /packages/automaton-fxs/README.md: -------------------------------------------------------------------------------- 1 | # automaton-fxs 2 | 3 | Bunch of automaton fxs 4 | -------------------------------------------------------------------------------- /packages/automaton-fxs-v2compat/README.md: -------------------------------------------------------------------------------- 1 | # automaton-fxs-v2compat 2 | 3 | v2 compat fxs 4 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/types/WithID.ts: -------------------------------------------------------------------------------- 1 | export interface WithID { 2 | $id: string; 3 | } 4 | -------------------------------------------------------------------------------- /readme-images/automaton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0b5vr/automaton/HEAD/readme-images/automaton.png -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/types/WithBypass.ts: -------------------------------------------------------------------------------- 1 | export interface WithBypass { 2 | bypass: boolean; 3 | } 4 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/svg.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | const component: 'svg'; 3 | export default component; 4 | } 5 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/utils/Resolution.ts: -------------------------------------------------------------------------------- 1 | export interface Resolution { 2 | width: number; 3 | height: number; 4 | } 5 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/utils/lofi.ts: -------------------------------------------------------------------------------- 1 | export function lofi( t: number, d: number ): number { 2 | return Math.floor( t / d ) * d; 3 | } 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/*.js 2 | /node_modules/** 3 | /packages/*/dist/** 4 | /packages/*/types/** 5 | /packages/*/ts*/** 6 | /packages/*/node_modules/** 7 | -------------------------------------------------------------------------------- /packages/automaton-fxs/src/tests/utils/jsonCopy.ts: -------------------------------------------------------------------------------- 1 | export function jsonCopy( fuck: T ): T { 2 | return JSON.parse( JSON.stringify( fuck ) ); 3 | } 4 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/utils/jsonCopy.ts: -------------------------------------------------------------------------------- 1 | export function jsonCopy( fuck: T ): T { 2 | return JSON.parse( JSON.stringify( fuck ) ); 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /packages/*/dist/ 3 | /packages/*/docs/ 4 | /packages/*/node_modules/ 5 | /packages/*/types/ 6 | /packages/*/ts*/ 7 | **/*.log 8 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // it's required to make vscode-jest work properly... 2 | module.exports = { 3 | "transform": { 4 | "^.+\\.tsx?$": "ts-jest" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "npmClient": "yarn", 3 | "useWorkspaces": true, 4 | "packages": [ 5 | "packages/*" 6 | ], 7 | "version": "4.3.0-alpha.0" 8 | } 9 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/readme-images/automaton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0b5vr/automaton/HEAD/packages/automaton-with-gui/readme-images/automaton.png -------------------------------------------------------------------------------- /packages/automaton-with-gui/readme-images/playground.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0b5vr/automaton/HEAD/packages/automaton-with-gui/readme-images/playground.gif -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/types/MinimizeOptions.ts: -------------------------------------------------------------------------------- 1 | export interface MinimizeOptions { 2 | precisionTime: number; 3 | precisionValue: number; 4 | } 5 | -------------------------------------------------------------------------------- /packages/automaton-fxs/src/utils/clamp.ts: -------------------------------------------------------------------------------- 1 | export function clamp( x: number, a: number, b: number ): number { 2 | return Math.min( Math.max( x, a ), b ); 3 | } 4 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/types/Serializable.ts: -------------------------------------------------------------------------------- 1 | export interface Serializable { 2 | serialize: () => T; 3 | deserialize: ( data: T ) => void; 4 | } 5 | -------------------------------------------------------------------------------- /packages/automaton-fxs-v2compat/src/utils/clamp.ts: -------------------------------------------------------------------------------- 1 | export function clamp( x: number, a: number, b: number ): number { 2 | return Math.min( Math.max( x, a ), b ); 3 | } 4 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/utils/clamp.ts: -------------------------------------------------------------------------------- 1 | export function clamp( t: number, min: number, max: number ): number { 2 | return t < min ? min : max < t ? max : t; 3 | } 4 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/types/ToastyParams.ts: -------------------------------------------------------------------------------- 1 | export interface ToastyParams { 2 | kind: 'error' | 'warning' | 'info'; 3 | message: string; 4 | timeout?: number; 5 | } 6 | -------------------------------------------------------------------------------- /packages/automaton/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": [ 4 | "./src" 5 | ], 6 | "exclude": [ 7 | "**/tests/**" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /packages/automaton-fxs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": [ 4 | "./src" 5 | ], 6 | "exclude": [ 7 | "**/tests/**" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/ResumeStorage.ts: -------------------------------------------------------------------------------- 1 | export interface ResumeStorage { 2 | isPlaying: boolean; 3 | time: number; 4 | loopRegion: { begin: number; end: number } | null; 5 | } 6 | -------------------------------------------------------------------------------- /packages/automaton/src/types/FxParam.ts: -------------------------------------------------------------------------------- 1 | export interface FxParam { 2 | name?: string; 3 | type: 'float' | 'int' | 'boolean'; 4 | default: any; 5 | min?: number; 6 | max?: number; 7 | } 8 | -------------------------------------------------------------------------------- /packages/automaton-fxs-v2compat/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": [ 4 | "./src" 5 | ], 6 | "exclude": [ 7 | "**/tests/**" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /packages/automaton-fxs/src/utils/smoothstep.ts: -------------------------------------------------------------------------------- 1 | export function smoothstep( a: number, b: number, k: number ): number { 2 | const smooth = k * k * ( 3.0 - 2.0 * k ); 3 | return a + ( b - a ) * smooth; 4 | } 5 | -------------------------------------------------------------------------------- /packages/automaton/src/types/AutomatonOptions.ts: -------------------------------------------------------------------------------- 1 | import type { FxDefinition } from './FxDefinition'; 2 | 3 | export interface AutomatonOptions { 4 | fxDefinitions?: { [ name: string ]: FxDefinition }; 5 | } 6 | -------------------------------------------------------------------------------- /packages/automaton-fxs-v2compat/src/utils/smoothstep.ts: -------------------------------------------------------------------------------- 1 | export function smoothstep( a: number, b: number, k: number ): number { 2 | const smooth = k * k * ( 3.0 - 2.0 * k ); 3 | return a + ( b - a ) * smooth; 4 | } 5 | -------------------------------------------------------------------------------- /packages/automaton-fxs/src/utils/smin.ts: -------------------------------------------------------------------------------- 1 | export function smin( a: number, b: number, k: number ): number { 2 | const h = Math.max( k - Math.abs( a - b ), 0.0 ); 3 | return Math.min( a, b ) - h * h * h / ( 6.0 * k * k ); 4 | } 5 | -------------------------------------------------------------------------------- /packages/automaton-fxs-v2compat/src/utils/smin.ts: -------------------------------------------------------------------------------- 1 | export function smin( a: number, b: number, k: number ): number { 2 | const h = Math.max( k - Math.abs( a - b ), 0.0 ); 3 | return Math.min( a, b ) - h * h * h / ( 6.0 * k * k ); 4 | } 5 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/utils/genID.ts: -------------------------------------------------------------------------------- 1 | export function genID(): string { 2 | let ret = ''; 3 | for ( let i = 0; i < 16; i ++ ) { 4 | ret += Math.floor( 16.0 * Math.random() ).toString( 16 ); 5 | } 6 | return ret; 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "strict": true, 6 | "moduleResolution": "node", 7 | "downlevelIteration": true, 8 | "lib": [ "es2020", "dom" ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /dev.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Automaton development index!!!!!!!! 5 | 6 | 7 |

haha

8 |

9 | automaton-with-gui 10 |

11 | 12 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/icons/play.svg: -------------------------------------------------------------------------------- 1 | 5 | 13 | 14 | -------------------------------------------------------------------------------- /packages/automaton/src/types/FxDefinition.ts: -------------------------------------------------------------------------------- 1 | import { FxContext } from './FxContext'; 2 | import { FxParam } from './FxParam'; 3 | 4 | export interface FxDefinition { 5 | name?: string; 6 | description?: string; 7 | params?: { [ key: string ]: FxParam }; 8 | func: ( context: FxContext ) => number; 9 | } 10 | -------------------------------------------------------------------------------- /packages/automaton/src/types/SerializedChannel.ts: -------------------------------------------------------------------------------- 1 | import type { SerializedChannelItem } from './SerializedChannelItem'; 2 | 3 | /** 4 | * Represents a serialized channel. 5 | */ 6 | export interface SerializedChannel { 7 | /** 8 | *List of channel items. 9 | */ 10 | items?: SerializedChannelItem[]; 11 | } 12 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/utils/clipboard.ts: -------------------------------------------------------------------------------- 1 | export function writeClipboard( text: string ): void { 2 | const el = document.createElement( 'textarea' ); 3 | el.value = text; 4 | 5 | document.body.appendChild( el ); 6 | el.select(); 7 | document.execCommand( 'copy' ); 8 | document.body.removeChild( el ); 9 | } 10 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/compat/v3types/V3SerializedChannel.ts: -------------------------------------------------------------------------------- 1 | import type { SerializedChannelItem } from '@0b5vr/automaton'; 2 | 3 | /** 4 | * Interface of a serialized channel. 5 | */ 6 | export interface V3SerializedChannel { 7 | /** 8 | *List of channel items. 9 | */ 10 | items?: SerializedChannelItem[]; 11 | } 12 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/constants/Metrics.ts: -------------------------------------------------------------------------------- 1 | export const Metrics = { 2 | rootFontSize: 16, 3 | headerHeight: 32, 4 | channelListWidth: 160, 5 | channelListEntyHeight: 20, 6 | inspectorWidth: 192, 7 | curveListWidth: 160, 8 | modeSelectorWidth: 36, 9 | curveListEntryHeight: 36, 10 | toastyWidth: 320 11 | }; 12 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/components/InspectorHr.tsx: -------------------------------------------------------------------------------- 1 | import { Colors } from '../constants/Colors'; 2 | import styled from 'styled-components'; 3 | 4 | const InspectorHr = styled.div` 5 | margin: 0.25rem 0; 6 | height: 0.125rem; 7 | width: 100%; 8 | background: ${ Colors.back3 }; 9 | `; 10 | 11 | export { InspectorHr }; 12 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/components/ContextMenuHr.tsx: -------------------------------------------------------------------------------- 1 | import { Colors } from '../constants/Colors'; 2 | import styled from 'styled-components'; 3 | 4 | const ContextMenuHr = styled.div` 5 | margin: 0.25rem 0; 6 | height: 0.125rem; 7 | width: 100%; 8 | background: ${ Colors.back3 }; 9 | `; 10 | 11 | export { ContextMenuHr }; 12 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/utils/testRectIntersection.ts: -------------------------------------------------------------------------------- 1 | export function testRectIntersection( 2 | ax0: number, 3 | ay0: number, 4 | ax1: number, 5 | ay1: number, 6 | bx0: number, 7 | by0: number, 8 | bx1: number, 9 | by1: number, 10 | ): boolean { 11 | return !( bx0 > ax1 || bx1 < ax0 || by0 > ay1 || by1 < ay0 ); 12 | } 13 | -------------------------------------------------------------------------------- /packages/automaton-fxs-v2compat/src/index.ts: -------------------------------------------------------------------------------- 1 | export { add } from './add'; 2 | export { cds } from './cds'; 3 | export { clamp } from './clamp'; 4 | export { exp } from './exp'; 5 | export { gravity } from './gravity'; 6 | export { lofi } from './lofi'; 7 | export { noise } from './noise'; 8 | export { pow } from './pow'; 9 | export { sine } from './sine'; 10 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/icons/pause.svg: -------------------------------------------------------------------------------- 1 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/icons/redo.svg: -------------------------------------------------------------------------------- 1 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/icons/undo.svg: -------------------------------------------------------------------------------- 1 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/utils/combineArraysUnique.ts: -------------------------------------------------------------------------------- 1 | export function combineArraysUnique( ...arrays: Array> ): Array { 2 | const known = new Set(); 3 | arrays.forEach( ( array ) => { 4 | array.forEach( ( el ) => { 5 | if ( !known.has( el ) ) { 6 | known.add( el ); 7 | } 8 | } ); 9 | } ); 10 | return [ ...known ]; 11 | } 12 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/utils/useID.ts: -------------------------------------------------------------------------------- 1 | import { DependencyList, useMemo } from 'react'; 2 | 3 | let globalId = 0; 4 | 5 | export function useID( deps?: DependencyList ): number { 6 | return useMemo( 7 | () => { 8 | globalId ++; 9 | return globalId; 10 | }, 11 | // eslint-disable-next-line react-hooks/exhaustive-deps 12 | deps ?? [] 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/compat/v3types/V3SerializedBezierControlPoint.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Serialized variant of {@link BezierControlPoint}. 3 | * Some values are optional. 4 | */ 5 | export interface V3SerializedBezierControlPoint { 6 | /** 7 | * Time of the control point. 8 | */ 9 | time: number; 10 | 11 | /** 12 | * Value of the control point. 13 | */ 14 | value: number; 15 | } 16 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/types/StateChannelItem.ts: -------------------------------------------------------------------------------- 1 | import { WithID } from './WithID'; 2 | 3 | export interface StateChannelItem { 4 | time: number; 5 | length: number; 6 | value: number; 7 | repeat: number; 8 | reset: boolean; 9 | curveId: string | null; 10 | speed: number; 11 | offset: number; 12 | amp: number; 13 | } 14 | 15 | export interface StateChannelItem extends WithID {} 16 | -------------------------------------------------------------------------------- /packages/automaton-fxs/src/add.ts: -------------------------------------------------------------------------------- 1 | import type { FxDefinition } from '@0b5vr/automaton'; 2 | 3 | export const add: FxDefinition = { 4 | name: 'Add', 5 | description: 'The simplest fx ever. Just add a constant value to the curve.', 6 | params: { 7 | value: { name: 'Value', type: 'float', default: 1.0 } 8 | }, 9 | func( context ) { 10 | return context.value + context.params.value; 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /packages/automaton-fxs-v2compat/src/add.ts: -------------------------------------------------------------------------------- 1 | import type { FxDefinition } from '@0b5vr/automaton'; 2 | 3 | export const add: FxDefinition = { 4 | name: 'Add', 5 | description: 'The simplest fx ever. Just add a constant value to the curve.', 6 | params: { 7 | value: { name: 'Value', type: 'float', default: 1.0 } 8 | }, 9 | func( context ) { 10 | return context.value + context.params.value; 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /packages/automaton-fxs/src/index.ts: -------------------------------------------------------------------------------- 1 | export { add } from './add'; 2 | export { cds } from './cds'; 3 | export { clamp } from './clamp'; 4 | export { exp } from './exp'; 5 | export { gravity } from './gravity'; 6 | export { hermitePatch } from './hermitePatch'; 7 | export { lofi } from './lofi'; 8 | export { noise } from './noise'; 9 | export { pow } from './pow'; 10 | export { repeat } from './repeat'; 11 | export { sine } from './sine'; 12 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "types": [ "react", "node", "jest" ], 5 | "resolveJsonModule": true, 6 | "allowSyntheticDefaultImports": true, 7 | "removeComments": false, 8 | "noUnusedLocals": true, 9 | "jsx": "react" 10 | }, 11 | "include": [ 12 | "./src" 13 | ], 14 | "exclude": [ 15 | "**/tests/**" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /packages/automaton/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "roots": [ 3 | "/src" 4 | ], 5 | "transform": { 6 | "^.+\\.tsx?$": "ts-jest" 7 | }, 8 | "testRegex": "[^.]*\.test\.tsx?$", 9 | "moduleFileExtensions": [ 10 | "ts", 11 | "tsx", 12 | "js", 13 | "jsx", 14 | "json", 15 | "node" 16 | ], 17 | "collectCoverageFrom": [ 18 | "**/*.{ts,tsx}", 19 | "!**/tests/**" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /packages/automaton-fxs/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "roots": [ 3 | "/src" 4 | ], 5 | "transform": { 6 | "^.+\\.tsx?$": "ts-jest" 7 | }, 8 | "testRegex": "[^.]*\.test\.tsx?$", 9 | "moduleFileExtensions": [ 10 | "ts", 11 | "tsx", 12 | "js", 13 | "jsx", 14 | "json", 15 | "node" 16 | ], 17 | "collectCoverageFrom": [ 18 | "**/*.{ts,tsx}", 19 | "!**/tests/**" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/compat/v2types/V2SerializedParam.ts: -------------------------------------------------------------------------------- 1 | import { V2BezierNode } from './V2BezierNode'; 2 | import { V2FxSection } from './V2FxSection'; 3 | 4 | /** 5 | * Interface of serialized param. 6 | */ 7 | export interface V2SerializedParam { 8 | /** 9 | * Bezier nodes of the param. 10 | */ 11 | nodes: V2BezierNode[]; 12 | 13 | /** 14 | * Fx sections of the param. 15 | */ 16 | fxs: V2FxSection[]; 17 | } 18 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "roots": [ 3 | "/src" 4 | ], 5 | "transform": { 6 | "^.+\\.tsx?$": "ts-jest" 7 | }, 8 | "testRegex": "[^.]*\.test\.tsx?$", 9 | "moduleFileExtensions": [ 10 | "ts", 11 | "tsx", 12 | "js", 13 | "jsx", 14 | "json", 15 | "node" 16 | ], 17 | "collectCoverageFrom": [ 18 | "**/*.{ts,tsx}", 19 | "!**/tests/**" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/utils/hasOverwrap.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Math 3 | * @param t1 time 1 4 | * @param l1 length 1 5 | * @param t2 time 2 6 | * @param l2 length 2 7 | */ 8 | export function hasOverwrap( t1: number, l1: number, t2: number, l2: number ): boolean { 9 | if ( l2 < l1 ) { return hasOverwrap( t2, l2, t1, l1 ); } 10 | 11 | return ( 12 | t2 < t1 && t1 < t2 + l2 || 13 | t2 < t1 + l1 && t1 + l1 < t2 + l2 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/compat/v2types/V2AutomatonGUISettings.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Interface for automaton GUI settings. 3 | */ 4 | export interface V2AutomatonGUISettings { 5 | /** 6 | * Whether snap is activeted or not. 7 | */ 8 | snapActive: boolean; 9 | 10 | /** 11 | * Interval of snap, in time axis. 12 | */ 13 | snapTime: number; 14 | 15 | /** 16 | * Interval of snap, in value axis. 17 | */ 18 | snapValue: number; 19 | } 20 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/utils/registerMouseNoDragEvent.ts: -------------------------------------------------------------------------------- 1 | import { registerMouseEvent } from './registerMouseEvent'; 2 | 3 | export function registerMouseNoDragEvent( 4 | handler: ( event: MouseEvent ) => void 5 | ): void { 6 | let isMoved = false; 7 | 8 | registerMouseEvent( 9 | () => { 10 | isMoved = true; 11 | }, 12 | ( event ) => { 13 | if ( !isMoved ) { 14 | handler( event ); 15 | } 16 | }, 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/utils/useDoubleClick.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useRef } from 'react'; 2 | 3 | export function useDoubleClick( interval = 250 ): () => boolean { 4 | const refLastClick = useRef( 0 ); 5 | 6 | return useCallback( 7 | () => { 8 | const date = Date.now(); 9 | const delta = date - refLastClick.current; 10 | refLastClick.current = date; 11 | return ( delta < interval ); 12 | }, 13 | [ interval ] 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /packages/automaton/src/types/SerializedCurve.ts: -------------------------------------------------------------------------------- 1 | import type { SerializedBezierNode } from './SerializedBezierNode'; 2 | import type { SerializedFxSection } from './SerializedFxSection'; 3 | 4 | /** 5 | * Interface of a serialized curve. 6 | */ 7 | export interface SerializedCurve { 8 | /** 9 | * Bezier nodes of the curve. 10 | */ 11 | nodes: SerializedBezierNode[]; 12 | 13 | /** 14 | * Fx sections of the curve. 15 | */ 16 | fxs?: SerializedFxSection[]; 17 | } 18 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/compat/v3types/V3SerializedCurve.ts: -------------------------------------------------------------------------------- 1 | import type { SerializedFxSection } from '@0b5vr/automaton'; 2 | import type { V3SerializedBezierNode } from './V3SerializedBezierNode'; 3 | 4 | /** 5 | * Interface of a serialized curve. 6 | */ 7 | export interface V3SerializedCurve { 8 | /** 9 | * Bezier nodes of the curve. 10 | */ 11 | nodes: V3SerializedBezierNode[]; 12 | 13 | /** 14 | * Fx sections of the curve. 15 | */ 16 | fxs?: SerializedFxSection[]; 17 | } 18 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/utils/useElement.ts: -------------------------------------------------------------------------------- 1 | import { useLayoutEffect, useState } from 'react'; 2 | 3 | export function useElement( 4 | ref: React.RefObject 5 | ): T | null { 6 | const [ element, setElement ] = useState( ref.current ); 7 | 8 | useLayoutEffect( 9 | () => { 10 | if ( ref.current !== element ) { 11 | setElement( ref.current ); 12 | } 13 | }, 14 | [ element, ref ] 15 | ); 16 | 17 | return element; 18 | } 19 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/utils/objectMap.ts: -------------------------------------------------------------------------------- 1 | type Keyable = number | string | symbol; 2 | 3 | export function objectMapSize( object: Record ): number { 4 | return Object.keys( object ).length; 5 | } 6 | 7 | export function objectMapValues( object: Record ): T[] { 8 | return Object.values( object ); 9 | } 10 | 11 | export function objectMapHas( object: Record, key: K ): boolean { 12 | return object[ key ] != null; 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "pwa-chrome", 9 | "request": "launch", 10 | "name": "Launch Chrome against localhost", 11 | "url": "http://localhost:10001/dev.html", 12 | "webRoot": "${workspaceFolder}" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/components/Anchor.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | // == element ====================================================================================== 4 | export interface AnchorProps { 5 | className?: string; 6 | href: string; 7 | children: React.ReactNode; 8 | } 9 | 10 | const Anchor = ( { className, href, children }: AnchorProps ): JSX.Element => ( 11 | 12 | { children } 13 | 14 | ); 15 | 16 | export { Anchor }; 17 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/icons/snap.svg: -------------------------------------------------------------------------------- 1 | 5 | 30 | 31 | -------------------------------------------------------------------------------- /packages/automaton/src/types/FxSection.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Interface of a fx section. 3 | */ 4 | export interface FxSection { 5 | /** 6 | * Beginning time of the section. 7 | */ 8 | time: number; 9 | 10 | /** 11 | * Time length of the section. 12 | */ 13 | length: number; 14 | 15 | /** 16 | * Row of the section. 17 | */ 18 | row: number; 19 | 20 | /** 21 | * Fx definition name of the section. 22 | */ 23 | def: string; 24 | 25 | /** 26 | * Params of the section. 27 | */ 28 | params: { [ key: string ]: any }; 29 | } 30 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/icons/save.svg: -------------------------------------------------------------------------------- 1 | 5 | 33 | 34 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/types/SerializableWithID.ts: -------------------------------------------------------------------------------- 1 | import { Serializable } from './Serializable'; 2 | import { WithID } from './WithID'; 3 | 4 | export abstract class SerializableWithID { 5 | public serializeWithID(): T & WithID { 6 | const data = this.serialize(); 7 | return { 8 | ...data, 9 | $id: this.$id 10 | }; 11 | } 12 | } 13 | 14 | export interface SerializableWithID extends Serializable {} 15 | 16 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 17 | export interface SerializableWithID extends WithID {} 18 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/index.ts: -------------------------------------------------------------------------------- 1 | export type { GUISettings } from './types/GUISettings'; 2 | export type { SerializedAutomatonWithGUI } from './types/SerializedAutomatonWithGUI'; 3 | export type { Status } from './types/Status'; 4 | export type { MinimizeOptions } from './types/MinimizeOptions'; 5 | export type { ToastyParams } from './types/ToastyParams'; 6 | 7 | export { AutomatonWithGUI } from './AutomatonWithGUI'; 8 | export { ChannelItemWithGUI } from './ChannelItemWithGUI'; 9 | export { ChannelWithGUI } from './ChannelWithGUI'; 10 | export { CurveWithGUI } from './CurveWithGUI'; 11 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/utils/applyMixins.ts: -------------------------------------------------------------------------------- 1 | export function applyMixins( derivedCtor: any, baseCtors: any[] ): void { 2 | baseCtors.forEach( ( baseCtor ) => { 3 | Object.getOwnPropertyNames( baseCtor.prototype ).forEach( ( name ) => { 4 | // we should not use constructor otherwise the class name will be changed 5 | if ( name !== 'constructor' ) { 6 | Object.defineProperty( 7 | derivedCtor.prototype, 8 | name, 9 | Object.getOwnPropertyDescriptor( baseCtor.prototype, name )! 10 | ); 11 | } 12 | } ); 13 | } ); 14 | } 15 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/compat/v3types/V3SerializedAutomatonWithGUI.ts: -------------------------------------------------------------------------------- 1 | import type { V3GUISettings } from './V3GUISettings'; 2 | import type { V3SerializedAutomaton } from './V3SerializedAutomaton'; 3 | 4 | export interface V3SerializedAutomatonWithGUI extends V3SerializedAutomaton { 5 | /** 6 | * Version of the automaton. 7 | */ 8 | version: string; 9 | 10 | /** 11 | * Labels of the automaton. 12 | */ 13 | labels?: { [ name: string ]: number }; 14 | 15 | /** 16 | * Field that contains [[GUISettings]]. 17 | */ 18 | guiSettings?: Partial; 19 | } 20 | -------------------------------------------------------------------------------- /packages/automaton/src/types/SerializedAutomaton.ts: -------------------------------------------------------------------------------- 1 | import type { SerializedChannel } from './SerializedChannel'; 2 | import type { SerializedCurve } from './SerializedCurve'; 3 | 4 | /** 5 | * Represents a serialized automaton data. 6 | */ 7 | export interface SerializedAutomaton { 8 | /** 9 | * Resolution of the timeline. 10 | */ 11 | resolution: number; 12 | 13 | /** 14 | * Curves of the automaton. 15 | */ 16 | curves: SerializedCurve[]; 17 | 18 | /** 19 | * Channels of the automaton. 20 | */ 21 | channels: [ name: string, channel: SerializedChannel ][]; 22 | } 23 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/constants/Colors.ts: -------------------------------------------------------------------------------- 1 | export const Colors = { 2 | black: '#000000', 3 | white: '#ffffff', 4 | 5 | back1: '#191a1f', 6 | back2: '#24272d', 7 | back3: '#30343b', 8 | back4: '#3b4249', 9 | back5: '#474f57', 10 | 11 | fore: '#d0edff', 12 | foresub: '#b9d3e3', 13 | foredark: '#97abb9', 14 | 15 | gray: '#697681', 16 | 17 | accentbright: '#53c5ff', 18 | accent: '#00aaff', 19 | accentdark: '#0080c0', 20 | fx: '#0fd895', 21 | errorDark: '#a30a4a', 22 | error: '#ff0066', 23 | errorBright: '#ec5fa3', 24 | warning: '#fc9821', 25 | info: '#53c5ff' 26 | }; 27 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/compat/v3types/V3SerializedAutomaton.ts: -------------------------------------------------------------------------------- 1 | import type { V3SerializedChannel } from './V3SerializedChannel'; 2 | import type { V3SerializedCurve } from './V3SerializedCurve'; 3 | 4 | /** 5 | * Interface of serialized automaton data. 6 | */ 7 | export interface V3SerializedAutomaton { 8 | /** 9 | * Resolution of the timeline. 10 | */ 11 | resolution: number; 12 | 13 | /** 14 | * Curves of the automaton. 15 | */ 16 | curves: V3SerializedCurve[]; 17 | 18 | /** 19 | * Channels of the automaton. 20 | */ 21 | channels: { [ name: string ]: V3SerializedChannel }; 22 | } 23 | -------------------------------------------------------------------------------- /packages/automaton-fxs/src/utils/xorshift.ts: -------------------------------------------------------------------------------- 1 | export class Xorshift { 2 | private __seed: number = 1; 3 | 4 | public constructor( seed?: number ) { 5 | this.set( seed ); 6 | } 7 | 8 | public gen( seed?: number ): number { 9 | if ( seed ) { this.set( seed ); } 10 | this.__seed = this.__seed ^ ( this.__seed << 13 ); 11 | this.__seed = this.__seed ^ ( this.__seed >>> 17 ); 12 | this.__seed = this.__seed ^ ( this.__seed << 5 ); 13 | return this.__seed / Math.pow( 2, 32 ) + 0.5; 14 | } 15 | 16 | public set( seed: number = 1 ): void { 17 | this.__seed = seed; 18 | } 19 | } 20 | 21 | export default Xorshift; 22 | -------------------------------------------------------------------------------- /packages/automaton-fxs-v2compat/src/utils/xorshift.ts: -------------------------------------------------------------------------------- 1 | export class Xorshift { 2 | private __seed: number = 1; 3 | 4 | public constructor( seed?: number ) { 5 | this.set( seed ); 6 | } 7 | 8 | public gen( seed?: number ): number { 9 | if ( seed ) { this.set( seed ); } 10 | this.__seed = this.__seed ^ ( this.__seed << 13 ); 11 | this.__seed = this.__seed ^ ( this.__seed >>> 17 ); 12 | this.__seed = this.__seed ^ ( this.__seed << 5 ); 13 | return this.__seed / Math.pow( 2, 32 ) + 0.5; 14 | } 15 | 16 | public set( seed: number = 1 ): void { 17 | this.__seed = seed; 18 | } 19 | } 20 | 21 | export default Xorshift; 22 | -------------------------------------------------------------------------------- /packages/automaton-fxs/src/exp.ts: -------------------------------------------------------------------------------- 1 | import type { FxDefinition } from '@0b5vr/automaton'; 2 | 3 | export const exp: FxDefinition = { 4 | name: 'Exponential Smoothing', 5 | description: 'Smooth the curve. Simple but good.', 6 | params: { 7 | factor: { name: 'Factor', type: 'float', default: 10.0, min: 0.0 } 8 | }, 9 | func( context ) { 10 | const v = context.value; 11 | 12 | if ( context.init ) { 13 | context.state.pos = v; 14 | } 15 | 16 | const k = Math.exp( -context.deltaTime * context.params.factor ); 17 | context.state.pos = context.state.pos * k + v * ( 1.0 - k ); 18 | return context.state.pos; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /packages/automaton/src/types/BezierNode.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents a bezier node. 3 | */ 4 | export interface BezierNode { 5 | /** 6 | * Time of the node. 7 | */ 8 | time: number; 9 | 10 | /** 11 | * Value of the node. 12 | */ 13 | value: number; 14 | 15 | /** 16 | * Bezier control point of inlet. Time. 17 | */ 18 | inTime: number; 19 | 20 | /** 21 | * Bezier control point of inlet. Value. 22 | */ 23 | inValue: number; 24 | 25 | /** 26 | * Bezier control point of outlet. Time. 27 | */ 28 | outTime: number; 29 | 30 | /** 31 | * Bezier control point of outlet. Value. 32 | */ 33 | outValue: number; 34 | } 35 | -------------------------------------------------------------------------------- /packages/automaton-fxs-v2compat/src/exp.ts: -------------------------------------------------------------------------------- 1 | import type { FxDefinition } from '@0b5vr/automaton'; 2 | 3 | export const exp: FxDefinition = { 4 | name: 'Exponential Smoothing', 5 | description: 'Smooth the curve. Simple but good.', 6 | params: { 7 | factor: { name: 'Factor', type: 'float', default: 10.0, min: 0.0 } 8 | }, 9 | func( context ) { 10 | const v = context.value; 11 | 12 | if ( context.init ) { 13 | context.state.pos = v; 14 | } 15 | 16 | const k = Math.exp( -context.deltaTime * context.params.factor ); 17 | context.state.pos = context.state.pos * k + v * ( 1.0 - k ); 18 | return context.state.pos; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/icons/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "plugins": [ 3 | "react-hooks", 4 | ], 5 | 6 | "env": { 7 | "browser": true 8 | }, 9 | 10 | "extends": [ 11 | "plugin:react/recommended" 12 | ], 13 | 14 | "rules": { 15 | // react-specifics 16 | "react/jsx-no-useless-fragment": [ "error" ], // sounds good, huh 17 | "react/display-name": [ "error" ], // yes please, it's very important to do performance monitoring 18 | "react-hooks/rules-of-hooks": [ "error" ], // yes it must be followed 19 | "react-hooks/exhaustive-deps": [ "warn" ], // best eslint rule ever 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /packages/automaton-fxs/src/sine.ts: -------------------------------------------------------------------------------- 1 | import type { FxDefinition } from '@0b5vr/automaton'; 2 | 3 | const TAU = Math.PI * 2.0; 4 | 5 | export const sine: FxDefinition = { 6 | name: 'Sinewave', 7 | description: 'Overlay a sinewave to the curve.', 8 | params: { 9 | amp: { name: 'Amp', type: 'float', default: 0.1 }, 10 | freq: { name: 'Frequency', type: 'float', default: 5.0 }, 11 | offset: { name: 'Offset', type: 'float', default: 0.0, min: 0.0, max: 1.0 } 12 | }, 13 | func( context ) { 14 | const v = context.value; 15 | const p = context.elapsed * context.params.freq + context.params.offset; 16 | return v + context.params.amp * Math.sin( p * TAU ); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/compat/v2types/V2FxSection.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Interface of a fx section. 3 | */ 4 | export interface V2FxSection { 5 | /** 6 | * Beginning time of the section. 7 | */ 8 | time: number; 9 | 10 | /** 11 | * Time length of the section. 12 | */ 13 | length: number; 14 | 15 | /** 16 | * Row of the section. 17 | */ 18 | row: number; 19 | 20 | /** 21 | * Whether the section would be bypassed or not. 22 | * Can be undefined. 23 | */ 24 | bypass?: boolean; 25 | 26 | /** 27 | * Fx definition name of the section. 28 | */ 29 | def: string; 30 | 31 | /** 32 | * Params of the section. 33 | */ 34 | params: any; 35 | } 36 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/utils/duplicateName.ts: -------------------------------------------------------------------------------- 1 | export function duplicateName( name: string, existingSet: Set ): string { 2 | const match = name.match( /_(\d+)$/ ); 3 | const i0 = match == null 4 | ? 1 5 | : ( parseInt( match[ 1 ] ) + 1 ); 6 | const basename = match == null 7 | ? name 8 | : name.substring( 0, name.length - match[ 0 ].length ); 9 | 10 | for ( let i = i0; i < 1E9; i ++ ) { 11 | const newName = `${ basename }_${ i }`; 12 | if ( !existingSet.has( newName ) ) { 13 | return newName; 14 | } 15 | } 16 | 17 | throw new Error( 'duplicateName: Couldn\'t create a duplicate name. Something really weird is happening 🤔' ); 18 | } 19 | -------------------------------------------------------------------------------- /packages/automaton-fxs-v2compat/src/sine.ts: -------------------------------------------------------------------------------- 1 | import type { FxDefinition } from '@0b5vr/automaton'; 2 | 3 | const TAU = Math.PI * 2.0; 4 | 5 | export const sine: FxDefinition = { 6 | name: 'Sinewave', 7 | description: 'Overlay a sinewave to the curve.', 8 | params: { 9 | amp: { name: 'Amp', type: 'float', default: 0.1 }, 10 | freq: { name: 'Frequency', type: 'float', default: 5.0 }, 11 | phase: { name: 'Phase', type: 'float', default: 0.0, min: 0.0, max: 1.0 } 12 | }, 13 | func( context ) { 14 | const v = context.value; 15 | const p = context.progress * context.params.freq + context.params.phase; 16 | return v + context.params.amp * Math.sin( p * TAU ); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /packages/automaton-fxs/src/pow.ts: -------------------------------------------------------------------------------- 1 | import type { FxDefinition } from '@0b5vr/automaton'; 2 | 3 | export const pow: FxDefinition = { 4 | name: 'Power', 5 | description: 'You got boost power!', 6 | params: { 7 | pow: { name: 'Power', type: 'float', default: 2.0 }, 8 | bias: { name: 'Bias', type: 'float', default: 0.0 }, 9 | positive: { name: 'Force Positive', type: 'boolean', default: false } 10 | }, 11 | func( context ) { 12 | const v = context.value - context.params.bias; 13 | const sign = context.params.positive ? 1.0 : Math.sign( v ); 14 | return Math.pow( 15 | Math.abs( v ), 16 | context.params.pow 17 | ) * sign + context.params.bias; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /packages/automaton-fxs-v2compat/src/pow.ts: -------------------------------------------------------------------------------- 1 | import type { FxDefinition } from '@0b5vr/automaton'; 2 | 3 | export const pow: FxDefinition = { 4 | name: 'Power', 5 | description: 'You got boost power!', 6 | params: { 7 | pow: { name: 'Power', type: 'float', default: 2.0 }, 8 | bias: { name: 'Bias', type: 'float', default: 0.0 }, 9 | positive: { name: 'Force Positive', type: 'boolean', default: false } 10 | }, 11 | func( context ) { 12 | const v = context.value - context.params.bias; 13 | const sign = context.params.positive ? 1.0 : Math.sign( v ); 14 | return Math.pow( 15 | Math.abs( v ), 16 | context.params.pow 17 | ) * sign + context.params.bias; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/icons/plus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/icons/beat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/automaton-fxs/src/repeat.ts: -------------------------------------------------------------------------------- 1 | import type { FxDefinition } from '@0b5vr/automaton'; 2 | 3 | export const repeat: FxDefinition = { 4 | name: 'Repeat', 5 | description: 'Repeat a section of the curve.', 6 | params: { 7 | interval: { name: 'Interval', type: 'float', default: 1.0, min: 0.0 }, 8 | }, 9 | func( context ) { 10 | if ( context.index === context.i1 ) { 11 | context.setShouldNotInterpolate( true ); 12 | } 13 | 14 | if ( 15 | ( context.elapsed + context.deltaTime ) % context.params.interval < context.deltaTime 16 | ) { 17 | context.setShouldNotInterpolate( true ); 18 | } 19 | 20 | return context.getValue( context.t0 + context.elapsed % context.params.interval ); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/icons/cog.svg: -------------------------------------------------------------------------------- 1 | 5 | 40 | 41 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/compat/v2types/V2BezierNode.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Interface of a bezier control point. 3 | */ 4 | export interface V2BezierControlPoint { 5 | /** 6 | * Time of the control point. 7 | */ 8 | time: number; 9 | 10 | /** 11 | * Value of the control point. 12 | */ 13 | value: number; 14 | } 15 | 16 | /** 17 | * Interface of a bezier node. 18 | */ 19 | export interface V2BezierNode { 20 | /** 21 | * Time of the node. 22 | */ 23 | time: number; 24 | 25 | /** 26 | * Value of the node. 27 | */ 28 | value: number; 29 | 30 | /** 31 | * Bezier control point of inlet. 32 | */ 33 | in?: V2BezierControlPoint; 34 | 35 | /** 36 | * Bezier control point of outlet. 37 | */ 38 | out?: V2BezierControlPoint; 39 | } 40 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/utils/useAnimationFrame.ts: -------------------------------------------------------------------------------- 1 | import { DependencyList, useEffect, useRef } from 'react'; 2 | 3 | export function useAnimationFrame( 4 | callback: ( delta: number ) => void, 5 | deps: DependencyList 6 | ): void { 7 | const refPrev = useRef( 0 ); 8 | 9 | useEffect( () => { 10 | let halt = false; 11 | const update = (): void => { 12 | if ( halt ) { return; } 13 | 14 | const now = Date.now(); 15 | callback( 0.001 * ( now - refPrev.current ) ); 16 | refPrev.current = now; 17 | 18 | requestAnimationFrame( update ); 19 | }; 20 | update(); 21 | 22 | return () => { 23 | halt = true; 24 | }; 25 | // eslint-disable-next-line react-hooks/exhaustive-deps 26 | }, [ callback, ...deps ] ); 27 | } 28 | -------------------------------------------------------------------------------- /packages/automaton/src/types/SerializedFxSection.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Serialized variant of {@link FxSection}. 3 | * Some values are optional. 4 | */ 5 | export interface SerializedFxSection { 6 | /** 7 | * Beginning time of the section. 8 | * `0.0` by default. 9 | */ 10 | time?: number; 11 | 12 | /** 13 | * Time length of the section. 14 | * `0.0` by default. 15 | */ 16 | length?: number; 17 | 18 | /** 19 | * Row of the section. 20 | * `0` by default. 21 | */ 22 | row?: number; 23 | 24 | /** 25 | * Whether the section would be bypassed or not. 26 | */ 27 | bypass?: boolean; 28 | 29 | /** 30 | * Fx definition name of the section. 31 | */ 32 | def: string; 33 | 34 | /** 35 | * Params of the section. 36 | */ 37 | params: { [ key: string ]: any }; 38 | } 39 | -------------------------------------------------------------------------------- /packages/automaton-with-gui/src/view/components/Labels.tsx: -------------------------------------------------------------------------------- 1 | import { Label } from './Label'; 2 | import { Resolution } from '../utils/Resolution'; 3 | import { TimeRange } from '../utils/TimeValueRange'; 4 | import { useSelector } from '../states/store'; 5 | import React from 'react'; 6 | 7 | const Labels = ( { range, size }: { 8 | range: TimeRange; 9 | size: Resolution; 10 | } ): JSX.Element => { 11 | const { labels } = useSelector( ( state ) => ( { 12 | labels: state.automaton.labels 13 | } ) ); 14 | 15 | return <> 16 | { Object.entries( labels ).map( ( [ name, time ] ) => ( 17 |