From 61f9934501ea918042e13d630f536508d0fae3ed Mon Sep 17 00:00:00 2001 From: 0b5vr <0b5vr@0b5vr.com> Date: Sun, 12 Mar 2023 14:44:07 +0900 Subject: [PATCH 1/9] fix: Fix channel.getValue binarySearch condition should be lte instead of lt, otherwise it doesn't react when an item just starts --- packages/automaton-with-gui/src/ChannelWithGUI.ts | 2 +- packages/automaton/src/Channel.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/automaton-with-gui/src/ChannelWithGUI.ts b/packages/automaton-with-gui/src/ChannelWithGUI.ts index 5b9ec3b..49162cb 100644 --- a/packages/automaton-with-gui/src/ChannelWithGUI.ts +++ b/packages/automaton-with-gui/src/ChannelWithGUI.ts @@ -120,7 +120,7 @@ export class ChannelWithGUI extends Channel implements Serializable ( item.time < time ) ); + const next = binarySearch( this.__items, ( item ) => ( item.time <= time ) ); // it's the first one! if ( next === 0 ) { diff --git a/packages/automaton/src/Channel.ts b/packages/automaton/src/Channel.ts index d278554..de7c749 100644 --- a/packages/automaton/src/Channel.ts +++ b/packages/automaton/src/Channel.ts @@ -96,7 +96,7 @@ export class Channel { return 0.0; } - const next = binarySearch( this.__items, ( item ) => ( item.time < time ) ); + const next = binarySearch( this.__items, ( item ) => ( item.time <= time ) ); // it's the first one! if ( next === 0 ) { From a931b1246c83a92941b761b47aee59ceac7828f7 Mon Sep 17 00:00:00 2001 From: 0b5vr <0b5vr@0b5vr.com> Date: Sun, 12 Mar 2023 14:44:51 +0900 Subject: [PATCH 2/9] docs: add a note about release I don't remember when I wrote this --- CONTRIBUTING.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..1a8192a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,20 @@ +# CONTRIBUTING.md + +It's just a memorandum for myself + +### Release + +- 1, Make sure you're on `dev` + +- 2, Run: + + ```sh + yarn lerna version --exact --no-push # will also inspects and builds + yarn lerna publish from-git --dist-tag latest + + git switch release + git merge dev + git push + ``` + +- 3, Add a release note to https://github.com/0b5vr/automaton/releases From 91b43d6e91ed8cb1ee3cedcf5e4358e7083b1722 Mon Sep 17 00:00:00 2001 From: 0b5vr <0b5vr@0b5vr.com> Date: Sun, 12 Mar 2023 14:46:34 +0900 Subject: [PATCH 3/9] feature: init value for each channel item.reset still changes the value back to zero :< I might want to improve this in the next breaking update --- .../automaton-with-gui/src/ChannelWithGUI.ts | 5 +-- packages/automaton/src/Channel.ts | 17 +++++++--- packages/automaton/src/tests/Channel.test.ts | 31 +++++++++++++------ .../automaton/src/types/SerializedChannel.ts | 6 ++++ 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/packages/automaton-with-gui/src/ChannelWithGUI.ts b/packages/automaton-with-gui/src/ChannelWithGUI.ts index 49162cb..e30f430 100644 --- a/packages/automaton-with-gui/src/ChannelWithGUI.ts +++ b/packages/automaton-with-gui/src/ChannelWithGUI.ts @@ -81,6 +81,7 @@ export class ChannelWithGUI extends Channel implements Serializable ( item.time <= time ) ); // it's the first one! if ( next === 0 ) { - return 0.0; + return this.__init; } const item = this.__items[ next - 1 ]; diff --git a/packages/automaton/src/Channel.ts b/packages/automaton/src/Channel.ts index de7c749..ec613df 100644 --- a/packages/automaton/src/Channel.ts +++ b/packages/automaton/src/Channel.ts @@ -16,12 +16,17 @@ export class Channel { /** * List of channel items. */ - protected __items: ChannelItem[] = []; + protected __items!: ChannelItem[]; /** * A cache of last calculated value. */ - protected __value: number = 0.0; + protected __value: number; + + /** + * The initial value of the channel. + */ + protected __init!: number; /** * The time that was used for the calculation of [[__lastValue]]. @@ -47,6 +52,7 @@ export class Channel { this.__automaton = automaton; this.deserialize( data ); + this.__value = this.__init; } /** @@ -65,6 +71,7 @@ export class Channel { */ public deserialize( data: SerializedChannel ): void { this.__items = data.items?.map( ( item ) => new ChannelItem( this.__automaton, item ) ) ?? []; + this.__init = data.init ?? 0.0; } /** @@ -73,7 +80,7 @@ export class Channel { */ public reset(): void { this.__time = -Infinity; - this.__value = 0; + this.__value = this.__init; this.__head = 0; } @@ -93,14 +100,14 @@ export class Channel { public getValue( time: number ): number { // no items??? damn if ( this.__items.length === 0 ) { - return 0.0; + return this.__init; } const next = binarySearch( this.__items, ( item ) => ( item.time <= time ) ); // it's the first one! if ( next === 0 ) { - return 0.0; + return this.__init; } const item = this.__items[ next - 1 ]; diff --git a/packages/automaton/src/tests/Channel.test.ts b/packages/automaton/src/tests/Channel.test.ts index c115d47..43272e5 100644 --- a/packages/automaton/src/tests/Channel.test.ts +++ b/packages/automaton/src/tests/Channel.test.ts @@ -20,7 +20,7 @@ describe( 'Channel', () => { automaton = new Automaton( data ); } ); - it( 'must be instantiated correctly', () => { + it( 'instantiates correctly', () => { const channel = new Channel( automaton, { items: [ { curve: 0, time: 0.1 } ], } ); @@ -28,7 +28,7 @@ describe( 'Channel', () => { } ); describe( 'getValue', () => { - it( 'must handle an item of a linear curve properly', () => { + it( 'handles an item of a linear curve properly', () => { const channel = new Channel( automaton, { items: [ { curve: 0, time: 0.1 } ], } ); @@ -37,7 +37,7 @@ describe( 'Channel', () => { expect( channel.getValue( 0.9 ) ).toBeCloseTo( 1.0 ); } ); - it( 'must handle an item of a constant curve properly', () => { + it( 'handles an item of a constant curve properly', () => { const channel = new Channel( automaton, { items: [ { curve: 1, time: 0.1 } ], } ); @@ -46,16 +46,16 @@ describe( 'Channel', () => { expect( channel.getValue( 0.9 ) ).toBeCloseTo( 2.0 ); } ); - it( 'must handle a constant item with reset properly', () => { + it( 'handles a constant item with reset properly', () => { const channel = new Channel( automaton, { items: [ { time: 0.5, length: 0.5, value: 1.0, reset: true } ], } ); - expect( channel.getValue( 0.3 ) ).toBeCloseTo( 0.0 ); - expect( channel.getValue( 0.6 ) ).toBeCloseTo( 1.0 ); - expect( channel.getValue( 1.2 ) ).toBeCloseTo( 0.0 ); + expect( channel.getValue( 0.0 ) ).toBeCloseTo( 0.0 ); + expect( channel.getValue( 0.5 ) ).toBeCloseTo( 1.0 ); + expect( channel.getValue( 1.0 ) ).toBeCloseTo( 0.0 ); } ); - it( 'must handle an item of a linear curve with reset properly', () => { + it( 'handles an item of a linear curve with reset properly', () => { const channel = new Channel( automaton, { items: [ { curve: 0, time: 0.1, reset: true } ], } ); @@ -64,7 +64,7 @@ describe( 'Channel', () => { expect( channel.getValue( 0.9 ) ).toBeCloseTo( 0.0 ); } ); - it( 'must handle an item of a linear curve with repeat properly', () => { + it( 'handles an item of a linear curve with repeat properly', () => { const channel = new Channel( automaton, { items: [ { curve: 0, time: 0.1, length: 2.0, repeat: 1.0 } ], } ); @@ -76,7 +76,7 @@ describe( 'Channel', () => { expect( channel.getValue( 1.7 ) ).toBeCloseTo( 1.0 ); } ); - it( 'must handle an item of a linear curve with repeat and offset properly', () => { + it( 'handles an item of a linear curve with repeat and offset properly', () => { const channel = new Channel( automaton, { items: [ { curve: 0, time: 0.1, length: 1.8, repeat: 1.0, offset: -0.3 } ], } ); @@ -90,5 +90,16 @@ describe( 'Channel', () => { expect( channel.getValue( 1.7 ) ).toBeCloseTo( 0.5 ); expect( channel.getValue( 1.95 ) ).toBeCloseTo( 0.833 ); } ); + + it( 'handles an initial value properly', () => { + const channel = new Channel( automaton, { + items: [ { time: 0.5, value: 2.0 } ], + init: 1.0, + } ); + expect( channel.getValue( 0.0 ) ).toBeCloseTo( 1.0 ); + expect( channel.getValue( 0.1 ) ).toBeCloseTo( 1.0 ); + expect( channel.getValue( 0.5 ) ).toBeCloseTo( 2.0 ); + expect( channel.getValue( 0.6 ) ).toBeCloseTo( 2.0 ); + } ); } ); } ); diff --git a/packages/automaton/src/types/SerializedChannel.ts b/packages/automaton/src/types/SerializedChannel.ts index 33ae672..8eb588a 100644 --- a/packages/automaton/src/types/SerializedChannel.ts +++ b/packages/automaton/src/types/SerializedChannel.ts @@ -8,4 +8,10 @@ export interface SerializedChannel { *List of channel items. */ items?: SerializedChannelItem[]; + + /** + * The initial value of the channel. + * If it's not defined, it will be `0.0`. + */ + init?: number; } From 13521cf07fb529e5b010857980f1d79d5448453c Mon Sep 17 00:00:00 2001 From: 0b5vr <0b5vr@0b5vr.com> Date: Sun, 12 Mar 2023 14:47:16 +0900 Subject: [PATCH 4/9] fix (gui): fix wording on channel item inspector (kinda trivial) --- .../src/view/components/InspectorChannelItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/automaton-with-gui/src/view/components/InspectorChannelItem.tsx b/packages/automaton-with-gui/src/view/components/InspectorChannelItem.tsx index 97770ce..981a69e 100644 --- a/packages/automaton-with-gui/src/view/components/InspectorChannelItem.tsx +++ b/packages/automaton-with-gui/src/view/components/InspectorChannelItem.tsx @@ -166,7 +166,7 @@ const InspectorChannelItem = ( props: Props ): JSX.Element | null => { return ( automaton && channel && stateItem && ( - + From 4fbaf74b94b1c2bb7be49ed620229c8b44d6b184 Mon Sep 17 00:00:00 2001 From: 0b5vr <0b5vr@0b5vr.com> Date: Sun, 12 Mar 2023 15:00:58 +0900 Subject: [PATCH 5/9] feature (gui): set init value of channels from gui --- .../automaton-with-gui/src/ChannelWithGUI.ts | 22 +++++++ .../components/AutomatonStateListener.tsx | 14 ++++ .../src/view/components/Inspector.tsx | 7 ++ .../src/view/components/InspectorChannel.tsx | 66 +++++++++++++++++++ .../src/view/history/HistoryCommand.ts | 12 ++++ .../src/view/states/Automaton.ts | 8 +++ 6 files changed, 129 insertions(+) create mode 100644 packages/automaton-with-gui/src/view/components/InspectorChannel.tsx diff --git a/packages/automaton-with-gui/src/ChannelWithGUI.ts b/packages/automaton-with-gui/src/ChannelWithGUI.ts index e30f430..502b210 100644 --- a/packages/automaton-with-gui/src/ChannelWithGUI.ts +++ b/packages/automaton-with-gui/src/ChannelWithGUI.ts @@ -45,6 +45,13 @@ export class ChannelWithGUI extends Channel implements Serializable { + refAccumActions.current.push( { + type: 'Automaton/ChangeChannelInit', + channel: name, + init, + } ); + } ); + channel.on( 'changeLength', ( { length } ) => { refAccumActions.current.push( { type: 'Automaton/UpdateChannelLength', diff --git a/packages/automaton-with-gui/src/view/components/Inspector.tsx b/packages/automaton-with-gui/src/view/components/Inspector.tsx index e04d072..af17d0c 100644 --- a/packages/automaton-with-gui/src/view/components/Inspector.tsx +++ b/packages/automaton-with-gui/src/view/components/Inspector.tsx @@ -2,6 +2,7 @@ import { Colors } from '../constants/Colors'; import { ErrorBoundary } from './ErrorBoundary'; import { Icons } from '../icons/Icons'; import { InspectorBeat } from './InspectorBeat'; +import { InspectorChannel } from './InspectorChannel'; import { InspectorChannelItem } from './InspectorChannelItem'; import { InspectorCurveFx } from './InspectorCurveFx'; import { InspectorCurveNode } from './InspectorCurveNode'; @@ -48,6 +49,7 @@ const Inspector = ( { className }: { selectedCurve, stateSelectedNodes, stateSelectedFxs, + stateSelectedChannel, stateSelectedTimelineItems, stateSelectedTimelineLabels, settingsMode, @@ -56,6 +58,7 @@ const Inspector = ( { className }: { selectedCurve: state.curveEditor.selectedCurve, stateSelectedNodes: state.curveEditor.selected.nodes, stateSelectedFxs: state.curveEditor.selected.fxs, + stateSelectedChannel: state.timeline.selectedChannel, stateSelectedTimelineItems: state.timeline.selected.items, stateSelectedTimelineLabels: state.timeline.selected.labels, settingsMode: state.settings.mode, @@ -94,6 +97,10 @@ const Inspector = ( { className }: { content = ; + } else if ( stateSelectedChannel != null ) { + content = ; } } diff --git a/packages/automaton-with-gui/src/view/components/InspectorChannel.tsx b/packages/automaton-with-gui/src/view/components/InspectorChannel.tsx new file mode 100644 index 0000000..425c3fd --- /dev/null +++ b/packages/automaton-with-gui/src/view/components/InspectorChannel.tsx @@ -0,0 +1,66 @@ +import { InspectorHeader } from './InspectorHeader'; +import { InspectorHr } from './InspectorHr'; +import { InspectorItem } from './InspectorItem'; +import { NumberParam } from './NumberParam'; +import { useDispatch, useSelector } from '../states/store'; +import React from 'react'; +import styled from 'styled-components'; + +// == styles ======================================================================================= +const Root = styled.div` +`; + +// == component ==================================================================================== +interface Props { + className?: string; + channelName: string; +} + +const InspectorChannel = ( props: Props ): JSX.Element | null => { + const { className, channelName } = props; + const dispatch = useDispatch(); + const { automaton, stateChannel } = useSelector( ( state ) => ( { + automaton: state.automaton.instance, + stateChannel: state.automaton.channels[ channelName ], + } ) ); + const channel = automaton?.getChannel( channelName ) ?? null; + + if ( + automaton == null || + channel == null + ) { + return null; + } + + return ( + + + + + + + channel.changeInit( value ) } + onSettle={ ( value, valuePrev ) => { + dispatch( { + type: 'History/Push', + description: 'Change Channel Init', + commands: [ + { + type: 'channel/changeInit', + channel: channelName, + init: value, + initPrev: valuePrev, + } + ], + } ); + } } + /> + + + ); +}; + +export { InspectorChannel }; diff --git a/packages/automaton-with-gui/src/view/history/HistoryCommand.ts b/packages/automaton-with-gui/src/view/history/HistoryCommand.ts index 78b9da4..c87b997 100644 --- a/packages/automaton-with-gui/src/view/history/HistoryCommand.ts +++ b/packages/automaton-with-gui/src/view/history/HistoryCommand.ts @@ -108,6 +108,11 @@ export type HistoryCommand = { item: string; amp: number; ampPrev: number; +} | { + type: 'channel/changeInit'; + channel: string; + init: number; + initPrev: number; } | { type: 'curve/createNodeFromData'; curveId: string; @@ -344,6 +349,13 @@ export function parseHistoryCommand( command: HistoryCommand ): { redo: ( automaton ) => automaton.getChannel( command.channel )! .changeCurveAmp( command.item, command.amp ) }; + } else if ( command.type === 'channel/changeInit' ) { + return { + undo: ( automaton ) => automaton.getChannel( command.channel )! + .changeInit( command.initPrev ), + redo: ( automaton ) => automaton.getChannel( command.channel )! + .changeInit( command.init ), + }; } else if ( command.type === 'curve/createNodeFromData' ) { return { undo: ( automaton ) => automaton.getCurveById( command.curveId )! diff --git a/packages/automaton-with-gui/src/view/states/Automaton.ts b/packages/automaton-with-gui/src/view/states/Automaton.ts index e12d071..f720327 100644 --- a/packages/automaton-with-gui/src/view/states/Automaton.ts +++ b/packages/automaton-with-gui/src/view/states/Automaton.ts @@ -26,6 +26,7 @@ export interface State { length: number; status: Status | null; items: { [ id: string ]: StateChannelItem }; + init: number; sortedItems: StateChannelItem[]; }; }; @@ -114,6 +115,10 @@ export type Action = { type: 'Automaton/RemoveChannelItem'; channel: string; id: string; +} | { + type: 'Automaton/ChangeChannelInit'; + channel: string; + init: number; } | { type: 'Automaton/CreateCurve'; curveId: string; @@ -223,6 +228,7 @@ export const reducer: Reducer = ( state = initialState, ac length: 1.0, status: null, items: {}, + init: 0.0, sortedItems: [], }; } else if ( action.type === 'Automaton/RemoveChannel' ) { @@ -277,6 +283,8 @@ export const reducer: Reducer = ( state = initialState, ac } delete newState.channels[ action.channel ].items[ action.id ]; + } else if ( action.type === 'Automaton/ChangeChannelInit' ) { + newState.channels[ action.channel ].init = action.init; } else if ( action.type === 'Automaton/CreateCurve' ) { newState.curves[ action.curveId ] = { status: null, From 3cefe7e30fc9f424d791ea6803affd20de39fdf6 Mon Sep 17 00:00:00 2001 From: 0b5vr <0b5vr@0b5vr.com> Date: Sun, 12 Mar 2023 15:08:04 +0900 Subject: [PATCH 6/9] refactor: replace map -> flat with flatMap --- packages/automaton/src/Automaton.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/automaton/src/Automaton.ts b/packages/automaton/src/Automaton.ts index 67f11e3..030f92b 100644 --- a/packages/automaton/src/Automaton.ts +++ b/packages/automaton/src/Automaton.ts @@ -175,7 +175,7 @@ export class Automaton { this.__time = t; // update channels - const array = this.channels.map( ( channel ) => channel.consume( this.__time ) ).flat( 1 ); + const array = this.channels.flatMap( ( channel ) => channel.consume( this.__time ) ); array.sort( ( [ a ], [ b ] ) => a - b ).forEach( ( [ _, func ] ) => func() ); } From 4a49f023325b16f00e3e512ea8902820a6dd8268 Mon Sep 17 00:00:00 2001 From: 0b5vr <0b5vr@0b5vr.com> Date: Sun, 12 Mar 2023 15:22:16 +0900 Subject: [PATCH 7/9] change: item reset will reset the value to channel init value instead of zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit it's now much better ✅ --- .../automaton-with-gui/src/ChannelItemWithGUI.ts | 3 ++- packages/automaton-with-gui/src/ChannelWithGUI.ts | 8 +++----- packages/automaton/src/Channel.ts | 14 +++++++------- packages/automaton/src/ChannelItem.ts | 15 +++++++++------ packages/automaton/src/tests/Channel.test.ts | 13 +++++++++++++ .../automaton/src/types/SerializedChannelItem.ts | 2 +- 6 files changed, 35 insertions(+), 20 deletions(-) diff --git a/packages/automaton-with-gui/src/ChannelItemWithGUI.ts b/packages/automaton-with-gui/src/ChannelItemWithGUI.ts index 24681e9..5f9a651 100644 --- a/packages/automaton-with-gui/src/ChannelItemWithGUI.ts +++ b/packages/automaton-with-gui/src/ChannelItemWithGUI.ts @@ -12,7 +12,8 @@ export class ChannelItemWithGUI extends ChannelItem { public curve?: CurveWithGUI; /** - * TODO + * Return a value of the item at the given timepoint. + * * @param time The timepoint you want to grab the value * @param isFromGUI If you're poking the method from Automaton GUI, set this to true otherwise you are going to suffer in redux hell */ diff --git a/packages/automaton-with-gui/src/ChannelWithGUI.ts b/packages/automaton-with-gui/src/ChannelWithGUI.ts index 502b210..ba97d11 100644 --- a/packages/automaton-with-gui/src/ChannelWithGUI.ts +++ b/packages/automaton-with-gui/src/ChannelWithGUI.ts @@ -136,11 +136,9 @@ export class ChannelWithGUI extends Channel implements Serializable { - this.__value = item.getValue( elapsed ); + this.__value = ( reset && end <= time ) + ? this.__init + : item.getValue( elapsed ); this.__listeners.forEach( ( listener ) => listener( { time, diff --git a/packages/automaton/src/ChannelItem.ts b/packages/automaton/src/ChannelItem.ts index 2002ae8..3d409cb 100644 --- a/packages/automaton/src/ChannelItem.ts +++ b/packages/automaton/src/ChannelItem.ts @@ -31,7 +31,9 @@ export class ChannelItem { public value!: number; /** - * Whether reset channels value to zero at the end of this item or not. + * Whether reset channels value to init at the end of this item or not. + * + * Impl note: `reset` will be considered by the Channel side, not the ChannelItem side. */ public reset?: boolean; @@ -76,14 +78,15 @@ export class ChannelItem { this.deserialize( data ); } + /** + * Return a value of the item at the given timepoint. + * + * @param time The timepoint you want to grab the value + */ public getValue( time: number ): number { - if ( this.reset && this.length <= time ) { - return 0.0; - } - if ( this.curve ) { const repeat = ( 0.0 < this.repeat && this.repeat < this.length ) ? this.repeat : Infinity; - const t = this.offset + ( time % repeat ) * this.speed; + const t = this.offset + ( Math.min( time, this.length ) % repeat ) * this.speed; return this.value + this.amp * this.curve.getValue( t ); } else { return this.value; diff --git a/packages/automaton/src/tests/Channel.test.ts b/packages/automaton/src/tests/Channel.test.ts index 43272e5..c9bf6ae 100644 --- a/packages/automaton/src/tests/Channel.test.ts +++ b/packages/automaton/src/tests/Channel.test.ts @@ -101,5 +101,18 @@ describe( 'Channel', () => { expect( channel.getValue( 0.5 ) ).toBeCloseTo( 2.0 ); expect( channel.getValue( 0.6 ) ).toBeCloseTo( 2.0 ); } ); + + it( 'handles an initial value + an item with reset properly', () => { + const channel = new Channel( automaton, { + items: [ { time: 0.5, value: 2.0, length: 0.5, reset: true } ], + init: 1.0, + } ); + expect( channel.getValue( 0.0 ) ).toBeCloseTo( 1.0 ); + expect( channel.getValue( 0.1 ) ).toBeCloseTo( 1.0 ); + expect( channel.getValue( 0.5 ) ).toBeCloseTo( 2.0 ); + expect( channel.getValue( 0.6 ) ).toBeCloseTo( 2.0 ); + expect( channel.getValue( 1.0 ) ).toBeCloseTo( 1.0 ); + expect( channel.getValue( 1.1 ) ).toBeCloseTo( 1.0 ); + } ); } ); } ); diff --git a/packages/automaton/src/types/SerializedChannelItem.ts b/packages/automaton/src/types/SerializedChannelItem.ts index 641cb86..5e44f7d 100644 --- a/packages/automaton/src/types/SerializedChannelItem.ts +++ b/packages/automaton/src/types/SerializedChannelItem.ts @@ -21,7 +21,7 @@ export interface SerializedChannelItem { value?: number; /** - * Whether reset channels value to zero at the end of this item or not. + * Whether reset channels value to init at the end of this item or not. * `false` by default. */ reset?: boolean; From e1f501abade52e08779ac863a51da573de69a29f Mon Sep 17 00:00:00 2001 From: 0b5vr <0b5vr@0b5vr.com> Date: Sun, 12 Mar 2023 15:22:29 +0900 Subject: [PATCH 8/9] feature: serialize channel init --- packages/automaton-with-gui/src/ChannelWithGUI.ts | 3 ++- packages/automaton-with-gui/src/minimizeData.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/automaton-with-gui/src/ChannelWithGUI.ts b/packages/automaton-with-gui/src/ChannelWithGUI.ts index ba97d11..c5bd7f1 100644 --- a/packages/automaton-with-gui/src/ChannelWithGUI.ts +++ b/packages/automaton-with-gui/src/ChannelWithGUI.ts @@ -203,7 +203,8 @@ export class ChannelWithGUI extends Channel implements Serializable minimizeChannelItem( item, options ) ); return { - items + items, + init: precOrUndefined( data.init, options.precisionValue ), }; } From 3ba66651b0b5395da9127a7430f114d4b1120f55 Mon Sep 17 00:00:00 2001 From: 0b5vr <0b5vr@0b5vr.com> Date: Sun, 12 Mar 2023 15:32:39 +0900 Subject: [PATCH 9/9] docs: update demo to use init value --- packages/automaton-with-gui/playground-examples/demo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/automaton-with-gui/playground-examples/demo.js b/packages/automaton-with-gui/playground-examples/demo.js index fc37617..d08b6f9 100644 --- a/packages/automaton-with-gui/playground-examples/demo.js +++ b/packages/automaton-with-gui/playground-examples/demo.js @@ -20,7 +20,7 @@ const context = canvas.getContext( '2d' ); // == initialize an automaton instance ============================================================= const automaton = new AUTOMATON_WITH_GUI.AutomatonWithGUI( JSON.parse( ` -{"version":"4.0.0","resolution":100,"curves":[{"nodes":[[0,0,0,0,0.06345177664974619],[0.2238578680203046,0.8088235294117649,-0.08883248730964469,-0.08921568627450979,0.08883248730964469,0.08921568627450979],[1,1,-0.47969543147208127]]},{"nodes":[[0,0,0,0,0.10913705583756345],[0.6000000000000001,1,-0.5507614213197969]]},{"nodes":[[],[0.1,1],[0.5,1],[0.6000000000000001],[1.8]],"fxs":[{"def":"cds","params":{"factor":300,"ratio":1,"preserve":false},"length":0.5},{"def":"gravity","params":{"a":30,"e":0.5,"preserve":true},"time":0.5,"length":0.728136781314195}]},{"nodes":[[0,1,0,0,0.05],[0.05,0,-0.05]]},{"nodes":[[],[1,1]]},{"nodes":[[0,0,0,0,0.2817258883248731],[0.4,1,-0.11421319796954314,-0.5970588235294118]]},{"nodes":[[],[4,1]]},{"nodes":[[],[0.1,1],[2,1]],"fxs":[{"def":"cds","params":{"factor":100,"ratio":1,"preserve":false},"length":2}]}],"channels":[["rect/x",{"items":[{"value":0.5}]}],["rect/y",{"items":[{"value":0.5},{"time":0.4,"length":1.3000000000000003,"value":0.5,"curve":2,"amp":-0.3},{"time":3.6,"length":0.40000000000000036,"value":0.5,"curve":5}]}],["rect/rotate",{"items":[{"time":0.2,"length":0.6,"curve":1},{"time":3.6,"length":0.40000000000000036,"curve":5,"amp":0.1}]}],["rect/sizeX",{"items":[{"time":0.2,"length":0.6,"curve":1,"amp":0.29999999999999993},{"time":1.9000000000000001,"length":0.15,"value":0.3,"curve":1,"speed":4,"amp":0.6000000000000001}]}],["rect/sizeY",{"items":[{"time":0.2,"length":0.6,"curve":1,"amp":0.29999999999999993}]}],["ring/radius0",{"items":[{"length":1,"curve":0}]}],["ring/radius1",{"items":[{"time":0.045685279187817264,"length":1,"curve":0,"amp":0.9}]}],["ring/radius2",{"items":[{"time":0.10152284263959391,"length":1,"curve":0,"amp":0.9}]}],["ring/radius3",{"items":[{"time":0.15228426395939088,"length":1,"curve":0,"amp":0.9}]}],["ring/radius4",{"items":[{"time":0.1979695431472081,"length":1,"curve":0,"amp":1.1}]}],["rect/bounce",{"items":[{"time":0.9,"length":0.8000000000000002,"value":1,"reset":true}]}],["dots/radius0",{"items":[{"time":1.5,"length":0.15,"curve":1,"speed":4,"amp":0.05}]}],["dots/radius1",{"items":[{"time":1.525,"length":0.15,"curve":1,"speed":4,"amp":0.05}]}],["dots/radius3",{"items":[{"time":1.55,"length":0.15,"curve":1,"speed":4,"amp":0.05}]}],["dots/radius2",{"items":[{"time":1.575,"length":0.15,"curve":1,"speed":4,"amp":0.05}]}],["rect/fill",{"items":[{"value":1},{"time":1.7000000000000002,"length":0.05,"curve":3},{"time":1.7500000000000002,"length":0.05,"curve":3},{"time":1.8000000000000003,"length":0.05,"curve":3}]}],["text/name",{"items":[{"time":2.1,"length":0.30000000000000027,"curve":4,"speed":3.33333333333334}]}],["text/description",{"items":[{"time":2.5,"length":0.8,"curve":4,"speed":1.25}]}],["zigzag/scroll",{"items":[{"time":0.5,"length":3.5,"value":0.5,"curve":6}]}],["zigzag/pos",{"items":[{"time":1.8,"length":1.2000000000000002,"curve":7,"amp":1.4},{"time":3.5,"length":0.40000000000000036,"value":1.4000000000000001,"curve":5,"amp":-1.4000000000000001}]}]],"labels":{"blink":1.7000000000000002,"wave":0,"text":2.1,"fall":3.6,"bounce":0.9},"guiSettings":{"snapTimeActive":true,"snapTimeInterval":0.1,"snapValueActive":true,"snapValueInterval":0.1,"snapBeatActive":false,"bpm":120,"beatOffset":0,"minimizedPrecisionTime":3,"minimizedPrecisionValue":3}} +{"version":"4.3.0","resolution":100,"curves":[{"nodes":[[0,0,0,0,0.06345177664974619],[0.2238578680203046,0.8088235294117649,-0.08883248730964469,-0.08921568627450979,0.08883248730964469,0.08921568627450979],[1,1,-0.47969543147208127]]},{"nodes":[[0,0,0,0,0.10913705583756345],[0.6000000000000001,1,-0.5507614213197969]]},{"nodes":[[],[0.1,1],[0.5,1],[0.6000000000000001],[1.8]],"fxs":[{"def":"cds","params":{"factor":300,"ratio":1,"preserve":false},"length":0.5},{"def":"gravity","params":{"a":30,"e":0.5,"preserve":true},"time":0.5,"length":0.728136781314195}]},{"nodes":[[0,1,0,0,0.05],[0.05,0,-0.05]]},{"nodes":[[],[1,1]]},{"nodes":[[0,0,0,0,0.2817258883248731],[0.4,1,-0.11421319796954314,-0.5970588235294118]]},{"nodes":[[],[4,1]]},{"nodes":[[],[0.1,1],[2,1]],"fxs":[{"def":"cds","params":{"factor":100,"ratio":1,"preserve":false},"length":2}]}],"channels":[["rect/x",{"items":[],"init":0.5}],["rect/y",{"items":[{"time":0.4,"length":1.3000000000000003,"value":0.5,"curve":2,"amp":-0.3},{"time":3.6,"length":0.40000000000000036,"value":0.5,"curve":5}],"init":0.5}],["rect/rotate",{"items":[{"time":0.2,"length":0.6,"curve":1},{"time":3.6,"length":0.40000000000000036,"curve":5,"amp":0.1}],"init":0}],["rect/sizeX",{"items":[{"time":0.2,"length":0.6,"curve":1,"amp":0.29999999999999993},{"time":1.9000000000000001,"length":0.15,"value":0.3,"curve":1,"speed":4,"amp":0.6000000000000001}],"init":0}],["rect/sizeY",{"items":[{"time":0.2,"length":0.6,"curve":1,"amp":0.29999999999999993}],"init":0}],["ring/radius0",{"items":[{"length":1,"curve":0}],"init":0}],["ring/radius1",{"items":[{"time":0.045685279187817264,"length":1,"curve":0,"amp":0.9}],"init":0}],["ring/radius2",{"items":[{"time":0.10152284263959391,"length":1,"curve":0,"amp":0.9}],"init":0}],["ring/radius3",{"items":[{"time":0.15228426395939088,"length":1,"curve":0,"amp":0.9}],"init":0}],["ring/radius4",{"items":[{"time":0.1979695431472081,"length":1,"curve":0,"amp":1.1}],"init":0}],["rect/bounce",{"items":[{"time":0.9,"length":0.8000000000000002,"value":1,"reset":true}],"init":0}],["dots/radius0",{"items":[{"time":1.5,"length":0.15,"curve":1,"speed":4,"amp":0.05}],"init":0}],["dots/radius1",{"items":[{"time":1.525,"length":0.15,"curve":1,"speed":4,"amp":0.05}],"init":0}],["dots/radius3",{"items":[{"time":1.55,"length":0.15,"curve":1,"speed":4,"amp":0.05}],"init":0}],["dots/radius2",{"items":[{"time":1.575,"length":0.15,"curve":1,"speed":4,"amp":0.05}],"init":0}],["rect/fill",{"items":[{"time":1.7000000000000002,"length":0.05,"curve":3},{"time":1.7500000000000002,"length":0.05,"curve":3},{"time":1.8000000000000003,"length":0.05,"curve":3}],"init":1}],["text/name",{"items":[{"time":2.1,"length":0.30000000000000027,"curve":4,"speed":3.33333333333334}],"init":0}],["text/description",{"items":[{"time":2.5,"length":0.8,"curve":4,"speed":1.25}],"init":0}],["zigzag/scroll",{"items":[{"time":0.5,"length":3.5,"value":0.5,"curve":6}],"init":0}],["zigzag/pos",{"items":[{"time":1.8,"length":1.2000000000000002,"curve":7,"amp":1.4},{"time":3.5,"length":0.40000000000000036,"value":1.4000000000000001,"curve":5,"amp":-1.4000000000000001}],"init":0}]],"labels":{"blink":1.7000000000000002,"wave":0,"text":2.1,"fall":3.6,"bounce":0.9},"guiSettings":{"snapTimeActive":true,"snapTimeInterval":0.1,"snapValueActive":true,"snapValueInterval":0.1,"snapBeatActive":false,"bpm":120,"beatOffset":0,"useBeatInGUI":false,"minimizedPrecisionTime":3,"minimizedPrecisionValue":3}} ` ), // put your automaton savedata here { gui: divAutomatonContainer, // where you want to put entire automaton GUI