From ee7300b22620423b73ee36c24ecc01f8afe5fbdc Mon Sep 17 00:00:00 2001 From: FMS-Cat Date: Sun, 28 Mar 2021 17:56:02 +0900 Subject: [PATCH] help --- src/Music.ts | 305 ------------------------------ src/automaton.json | 2 +- src/config.ts | 6 +- src/entities/IBLLUT.ts | 13 +- src/entities/LightEntity.ts | 11 +- src/globals/automaton.ts | 4 +- src/globals/music.ts | 8 +- src/main.ts | 35 ++-- src/music/AutomatonManager.ts | 99 ++++++++++ src/music/Music.ts | 178 +++++++++++++++++ src/music/MusicOffline.ts | 67 +++++++ src/music/MusicRealtime.ts | 55 ++++++ src/music/SamplesManager.ts | 62 ++++++ src/{shaders => music}/music.vert | 0 src/{ => music}/samples.opus | Bin src/scene.ts | 12 +- 16 files changed, 514 insertions(+), 343 deletions(-) delete mode 100644 src/Music.ts create mode 100644 src/music/AutomatonManager.ts create mode 100644 src/music/Music.ts create mode 100644 src/music/MusicOffline.ts create mode 100644 src/music/MusicRealtime.ts create mode 100644 src/music/SamplesManager.ts rename src/{shaders => music}/music.vert (100%) rename src/{ => music}/samples.opus (100%) diff --git a/src/Music.ts b/src/Music.ts deleted file mode 100644 index 7c28c2c..0000000 --- a/src/Music.ts +++ /dev/null @@ -1,305 +0,0 @@ -import { Channel } from '@fms-cat/automaton'; -import { GLCat, GLCatBuffer, GLCatProgram, GLCatTexture, GLCatTransformFeedback } from '@fms-cat/glcat-ts'; -import { MUSIC_AUTOMATON_TEXTURE_HEIGHT, MUSIC_BPM, MUSIC_BUFFER_LENGTH } from './config'; -import { Pool } from './utils/Pool'; -import { automaton } from './globals/automaton'; -import { gl, glCat } from './globals/canvas'; -import { injectCodeToShader } from './utils/injectCodeToShader'; -import { randomTextureStatic } from './globals/randomTexture'; -import musicVert from './shaders/music.vert'; -import samplesOpus from './samples.opus'; -import type { AutomatonWithGUI } from '@fms-cat/automaton-with-gui'; - -const discardFrag = '#version 300 es\nvoid main(){discard;}'; - -export class Music { - public isPlaying: boolean; - public time: number; - public deltaTime: number; - public audio: AudioContext; - - private __program: GLCatProgram; - private __bufferOff: GLCatBuffer; - private __bufferTransformFeedbacks: [ - GLCatBuffer, - GLCatBuffer - ]; - private __transformFeedback: GLCatTransformFeedback; - private __prevAudioTime: number; - private __bufferPool: Pool; - private __prevBufferSource: AudioBufferSourceNode | null = null; - private __samples?: GLCatTexture; - private __automatonChannelList: Channel[]; - private __automatonDefineString: string; - private __arrayAutomaton: Float32Array; - private __textureAutomaton: GLCatTexture; - - public constructor( glCat: GLCat, audio: AudioContext ) { - this.audio = audio; - - // == yoinked from wavenerd-deck =============================================================== - const bufferOffArray = new Array( MUSIC_BUFFER_LENGTH ) - .fill( 0 ) - .map( ( _, i ) => i ); - this.__bufferOff = glCat.createBuffer(); - this.__bufferOff.setVertexbuffer( new Float32Array( bufferOffArray ) ); - - this.__bufferTransformFeedbacks = [ - glCat.createBuffer(), - glCat.createBuffer(), - ]; - this.__transformFeedback = glCat.createTransformFeedback(); - - this.__bufferTransformFeedbacks[ 0 ].setVertexbuffer( - MUSIC_BUFFER_LENGTH * 4, - gl.STREAM_READ - ); - - this.__bufferTransformFeedbacks[ 1 ].setVertexbuffer( - MUSIC_BUFFER_LENGTH * 4, - gl.STREAM_READ - ); - - this.__transformFeedback.bindBuffer( 0, this.__bufferTransformFeedbacks[ 0 ] ); - this.__transformFeedback.bindBuffer( 1, this.__bufferTransformFeedbacks[ 1 ] ); - - // == automaton? =============================================================================== - this.__automatonChannelList = []; - this.__automatonDefineString = ''; - - this.__updateAutomatonChannelList(); - - this.__arrayAutomaton = new Float32Array( - MUSIC_BUFFER_LENGTH * MUSIC_AUTOMATON_TEXTURE_HEIGHT - ); - - this.__textureAutomaton = glCat.createTexture(); - this.__textureAutomaton.textureFilter( gl.NEAREST ); - - // == program ================================================================================== - this.__program = glCat.lazyProgram( - injectCodeToShader( musicVert, this.__automatonDefineString ), - discardFrag, - { transformFeedbackVaryings: [ 'outL', 'outR' ] }, - ); - - // == audio ==================================================================================== - this.__prevAudioTime = 0; - - this.__bufferPool = new Pool( [ - audio.createBuffer( 2, MUSIC_BUFFER_LENGTH, audio.sampleRate ), - audio.createBuffer( 2, MUSIC_BUFFER_LENGTH, audio.sampleRate ), - ] ); - - this.__loadSamples(); - - // == I think these are gonna be required ====================================================== - this.isPlaying = false; - this.time = 0.0; - this.deltaTime = 0.0; - - // == hot hot hot hot hot ====================================================================== - if ( process.env.DEV && module.hot ) { - const recompileShader = async (): Promise => { - const program = await glCat.lazyProgramAsync( - injectCodeToShader( musicVert, this.__automatonDefineString ), - discardFrag, - { transformFeedbackVaryings: [ 'outL', 'outR' ] }, - ).catch( ( error: any ) => { - console.error( error ); - return null; - } ); - - if ( program ) { - this.__program.dispose( true ); - this.__program = program; - } - }; - - module.hot.accept( - [ './shaders/music.vert' ], - () => { - recompileShader(); - } - ); - - module.hot.accept( - [ './automaton.json' ], - () => { - this.__updateAutomatonChannelList(); - recompileShader(); - } - ); - - ( automaton as AutomatonWithGUI ).on( 'createChannel', ( { name } ) => { - if ( name.startsWith( 'Music/' ) ) { - this.__updateAutomatonChannelList(); - recompileShader(); - } - } ); - - ( automaton as AutomatonWithGUI ).on( 'removeChannel', ( { name } ) => { - if ( name.startsWith( 'Music/' ) ) { - this.__updateAutomatonChannelList(); - recompileShader(); - } - } ); - } - } - - public update(): void { - const { audio, isPlaying } = this; - - const genTime = audio.currentTime; - - if ( isPlaying ) { - this.deltaTime = genTime - this.__prevAudioTime; - this.time += this.deltaTime; - - const buffer = this.__bufferPool.next(); - - if ( this.__program ) { - this.__updateAutomatonTexture(); - this.__prepareBuffer( buffer ); - } - - const bufferSource = audio.createBufferSource(); - bufferSource.buffer = buffer; - bufferSource.connect( audio.destination ); - - this.__prevBufferSource?.stop( audio.currentTime ); - bufferSource.start( audio.currentTime, audio.currentTime - genTime ); - this.__prevBufferSource = bufferSource; - } else { - this.deltaTime = 0.0; - - this.__prevBufferSource?.stop( audio.currentTime ); - this.__prevBufferSource = null; - } - - this.__prevAudioTime = genTime; - } - - private async __loadSamples(): Promise { - const inputBuffer = await fetch( samplesOpus ).then( ( res ) => res.arrayBuffer() ); - const audioBuffer = await this.audio.decodeAudioData( inputBuffer ); - - const buffer = new Float32Array( 96000 ); - - const data = audioBuffer.getChannelData( 0 ); - for ( let i = 0; i < audioBuffer.length; i ++ ) { - buffer[ i ] = data[ i ]; - } - - const texture = glCat.createTexture()!; - texture.setTextureFromArray( - 6000, - 16, - buffer, - { - internalformat: gl.R32F, - format: gl.RED, - type: gl.FLOAT, - } - ); - texture.textureFilter( gl.LINEAR ); - - this.__samples = texture; - } - - private __updateAutomatonChannelList(): void { - this.__automatonChannelList = []; - this.__automatonDefineString = ''; - - for ( const [ channelName, channel ] of automaton.mapNameToChannel.entries() ) { - if ( channelName.startsWith( 'Music/' ) ) { - const key = channelName.substring( 6 ); - const index = this.__automatonChannelList.length; - const y = ( index + 0.5 ) / MUSIC_AUTOMATON_TEXTURE_HEIGHT; - this.__automatonDefineString += `const float AUTO_${key}=${y};`; - this.__automatonChannelList.push( channel ); - } - } - } - - private __updateAutomatonTexture(): void { - for ( const [ iChannel, channel ] of this.__automatonChannelList.entries() ) { - for ( let iSample = 0; iSample < MUSIC_BUFFER_LENGTH; iSample ++ ) { - const t = this.time + iSample / this.audio.sampleRate; - this.__arrayAutomaton[ MUSIC_BUFFER_LENGTH * iChannel + iSample ] = channel.getValue( t ); - } - } - - this.__textureAutomaton.setTextureFromArray( - MUSIC_BUFFER_LENGTH, - MUSIC_AUTOMATON_TEXTURE_HEIGHT, - this.__arrayAutomaton, - { - internalformat: gl.R32F, - format: gl.RED, - type: gl.FLOAT, - } - ); - } - - private __prepareBuffer( buffer: AudioBuffer ): void { - const { time } = this; - const program = this.__program; - - const beatLength = 60.0 / MUSIC_BPM; - const barLength = 240.0 / MUSIC_BPM; - const sixteenBarLength = 3840.0 / MUSIC_BPM; - - program.attribute( 'off', this.__bufferOff, 1 ); - program.uniform( 'bpm', '1f', MUSIC_BPM ); - program.uniform( 'bufferLength', '1f', MUSIC_BUFFER_LENGTH ); - program.uniform( '_deltaSample', '1f', 1.0 / this.audio.sampleRate ); - program.uniform( - 'timeLength', - '4f', - beatLength, - barLength, - sixteenBarLength, - 1E16 - ); - program.uniform( - '_timeHead', - '4f', - time % beatLength, - time % barLength, - time % sixteenBarLength, - time, - ); - - program.uniformTexture( 'samplerRandom', randomTextureStatic.texture ); - program.uniformTexture( 'samplerAutomaton', this.__textureAutomaton ); - - if ( this.__samples ) { - program.uniformTexture( 'samplerSamples', this.__samples ); - } - - glCat.useProgram( program, () => { - glCat.bindTransformFeedback( this.__transformFeedback, () => { - gl.enable( gl.RASTERIZER_DISCARD ); - gl.beginTransformFeedback( gl.POINTS ); - gl.drawArrays( gl.POINTS, 0, MUSIC_BUFFER_LENGTH ); - gl.endTransformFeedback(); - gl.disable( gl.RASTERIZER_DISCARD ); - } ); - } ); - - gl.flush(); - - [ 0, 1 ].map( ( i ) => { - glCat.bindVertexBuffer( this.__bufferTransformFeedbacks[ i ], () => { - gl.getBufferSubData( - gl.ARRAY_BUFFER, - 0, - buffer.getChannelData( i ), - 0, - MUSIC_BUFFER_LENGTH - ); - } ); - } ); - } -} diff --git a/src/automaton.json b/src/automaton.json index 65433f0..1a98821 100644 --- a/src/automaton.json +++ b/src/automaton.json @@ -1 +1 @@ -{"version":"4.1.1","resolution":100,"curves":[{"nodes":[[0,1,0,0,0.16140350877192983],[1,0,-0.47719298245614045]]},{"nodes":[[0,0,0,0,0.1],[0.3747555183012014,1,-0.1,0,0.1],[1.3333333333333333,0,-0.1]]},{"nodes":[[],[0.6666666666666666,1,-0.4560629631300563,-0.1852941176470587],[0.6666666666666666,0,0,0,0.26644908616188,0.1029411764705882],[2,1.1900000000000002,-0.1],[2,0.00686274509803933,0,0,0.10652741514360319],[2.6666666666666665,0.7000000000000001],[2.6666666666666665,0,0,0,0.1391644908616188,0.5215686274509802],[3.333333333333333,0.9,-0.5014360313315928,-0.22647058823529403],[3.333333333333333,0,0,0,0.3974946346535474,0.10043744264185422],[4.666666666666666,1.2000000000000002,0,0,0.1],[4.666666666666666],[5.333333333333333,0.7000000000000001,-0.24079400848586707,-0.49736814906842436],[5.333333333333333],[6,0.8,-0.4356422056174482,-0.17156862745098037],[6,0,0,0,0.32852235276081576,0.05490196078431372],[7.333333333333333,1.1441176470588237,-0.1,0,0.1],[7.333333333333333],[8,0.3333],[8,0,0,0,0.08806743643105143,0.4254901960784307],[8.666666666666666,0.9,-0.3995834676293276,-0.08230605476940031],[8.666666666666666],[9.4,1.1,-0.2785205844025618,-0.17156862745098012,0.2785205844025618,0.17156862745098012],[10,1.3],[10],[10.666666666666666,0.6000000000000001,-0.11225401796276425,-0.5783350570563074]],"fxs":[{"def":"repeat","params":{"interval":0.2299999999999996},"time":7.333333333333333,"length":0.6666666666666667}]},{"nodes":[[0,0,0,0,0.12284595300261082,0.061764705882352944],[0.6666666666666666,0.4,-0.1],[0.6666666666666666,0.06568627450980391],[2,0.2],[2.236344893790143,0.4,-0.1,0,0.1],[2.6666666666666665,0,-0.34575086532310695,0,0.04271204452939744],[2.769918291305192,0.1,-0.05130523784998782,0,0.09999999999999999],[3.333333333333333,0.1],[3.6666666666666665,0.32774323388394533],[4.666666666666666,0.30000000000000004],[4.666666666666666,0.023323265139934546],[5.333333333333333,0.1],[5.333333333333333],[6,0.30000000000000004],[6,0.02745098039215696,0,0,0.09974597868276715,-0.006845312262542842],[7.333333333333333,0.1,-0.1],[7.333333333333333,0.7000000000000001],[8.666666666666666,0.7000000000000001],[8.666666666666666,1],[10,0.1],[10.666666666666666]]},{"nodes":[[0,0,0,0,0.1],[0.3333333333333333,1,-0.1,0,0.1],[0.6666666666666666,0,-0.1],[1.9166666666666665,1,-1.0007832898172324,0,0.06],[2],[2.025071712633245,1,-0.044516971279373374,0,0.1],[2.1623944411350506,0.5,-0.07221383357420871,0.2738348538091391,0.07221383357420871,-0.2738348538091391],[2.6666666666666665,0,-0.1,0,0.1],[3,1,-0.2864316909347707,0,0.24406085208595923],[3.333333333333333,0,-0.036443741726782705,0.4106336078810942],[3.6666666666666665,0.7544057184393509,-0.08631141286229893,-0.07178801363349067,0.13346814639852406,0.11100980502520727],[4.666666666666666,1,-0.33942558746736295,-0.018347344929083464,0.09208797505724492,-0.3264027483296351],[4.851079899134173,0.30000000000000004,-0.07486057061026631,-0.013179150760383026,0.1],[5.0444017511428605,0.9656862745098039,-0.1,0,0.1],[5.333333333333333,0.044689231228471016,-0.1,0,0.1],[5.666666666666666,1,-0.1,0,0.1],[6,0,-0.1],[7.333333333333333,1,-1.0426547051383652,0,0.1],[7.6000000000000005,0.7000000000000001,-0.1,0,0.1],[8,1],[8,0,-0.1,0,0.1],[8.166666666666666,1,-0.099988538641853,-0.006965859231865531],[8.489362746562259,1,0,0,0.09998887794379856,-0.006861981819672439],[8.666666666666666,0,-0.11262160793957762,0.041182622607896624],[8.9,1,-0.11617352813418727,-0.020588235294117612,0.11617352813418727,0.020588235294117612],[9.04400609908224,0.15784313725490162,-0.0988340957186134,-0.027450980392156817,0.0988340957186134,0.027450980392156817],[9.3,1,-0.09200304954112025,-0.041176470588235224,0.09200304954112025,0.041176470588235224],[9.5,0.2,-0.09449923761471994,-0.06176470588235285,0.09449923761471994,0.06176470588235285],[9.666666666666666,1,-0.08899847522943988,-0.027450980392156817,0.08899847522943988,0.027450980392156817],[10,0.30000000000000004,-0.06149466330303955,-0.06176470588235285,0.06149466330303955,0.06176470588235285],[10,1,-0.1,0,0.1],[10.666666666666666,0.1,-0.1,0,0.1]],"fxs":[{"def":"repeat","params":{"interval":0.2490000000000001},"time":2,"length":0.6666666666666665},{"def":"sine","params":{"amp":0.26,"freq":8.590000000000002,"offset":0},"time":3.934411837854859,"length":0.7322548288118069},{"def":"sine","params":{"amp":0.4400000000000004,"freq":5.889999999999998,"offset":0},"time":10.234266741175261,"length":0.4323999254914046},{"def":"hermitePatch","params":{},"time":3.821100533282267,"length":0.12610951070520438,"row":1},{"def":"hermitePatch","params":{},"time":10.18270758125172,"length":0.09198590579094379,"row":1}]},{"nodes":[[],[0.5,0.5,0,0,0.3072250626170559,0.32683448369273865],[1.3333333333333333,1.5]]},{"nodes":[[0,0.2,0,0,0.18674781789871728,2.609799325705191],[0.6666666666666666,0.1,-0.3546547911950566,0.44607843137254866]]},{"nodes":[[0,0.15115889256979576,0,0,0.1],[1.3333333333333333,0.7344636184844164,-0.8192982456140352,-0.01372549019607843]],"fxs":[{"def":"sine","params":{"amp":0.42000000000000004,"freq":9.43,"offset":0},"time":0.5833333333333333,"length":0.75},{"def":"hermitePatch","params":{},"time":0.5,"length":0.16666666666666663,"row":1}]},{"nodes":[[0,0,0,0,0.1],[0.6666666666666666,1,-0.1],[0.6666666666666666,0.04000000000000001],[2,0.019999999999999997],[2,0.4],[2.6666666666666665],[3.333333333333333,0.2,-0.1],[3.333333333333333,0.5],[4.666666666666666,0.6000000000000001],[4.666666666666666,0.059594068084455554],[5.333333333333333],[6,0.1],[7.333333333333333,0,-1.3219093627620064,-0.061764705882352944],[8],[8,0.8],[10,0.8],[10,0.1],[10.666666666666666]]},{"nodes":[[0,0,0,0,0.11631853785900784,0.15784313725490196],[0.3333333333333333,0.2,-0.1,-0.06862745098039215],[0.3333333333333333,0,0,0,0.10652741514360313,0.034313725490196074],[0.6257615317667536,0.4,-0.035197899213743125,-0.1178437887562426,0.05762038784328031,0.19291505927163513],[1.5833333333333333,1.6588235294117648,-0.14423846823324632,-0.08235294117647059],[1.5833333333333333,0,0,0,0.0706266318537859,0.12352941176470589],[1.8333333333333333,0.6000000000000001,-0.07923141560987097,-0.16655319476142408,0.05223508415950609,0.10980392156862741],[2,0.8,-0.07118673688066018,-0.08235294117647059]]},{"nodes":[[0,0.7000000000000001,0,0,0.14895561357702347,-0.7343137254901958],[0.6666666666666666,0.01999999999999999,-0.07958650842810296,0.0005266470222471706,0.7602446192333546,-0.005030759268204068],[1.75,0.2,-0.175065274151436,-0.0480392156862745],[2,1,-0.1]]},{"nodes":[[0,0.264705882352941,0,0,0.2664490861618798,-0.3705882352941175],[1.75,0,-0.1,0,0.1],[2,1,-0.1]]},{"nodes":[[0,0,0,0,0.1],[0.3333333333333333,0.9460784313725474,-0.1,0,0.1],[1.3333333333333333,0.3627450980392144,-0.11276290315437737,0.31798356313506776,0.058202350589290165,-0.16412659044332573],[1.6666666666666665,1,-0.1,0,0.1],[1.7304177545691903,0.1,-0.1,0,0.1],[2,1.4000000000000001,-0.05099116999738633,-0.5930547707442783]],"fxs":[{"def":"sine","params":{"amp":0.3999999999999999,"freq":17.779999999999987,"offset":0},"time":0.6103133159268926,"length":0.7230200174064406},{"def":"hermitePatch","params":{},"time":0.5580939947780674,"length":0.08289817232376029,"row":1},{"def":"hermitePatch","params":{},"time":1.2836814621409922,"length":0.11631853785900792,"row":1}]},{"nodes":[[0,1,0,0,0.06843643544269563,-0.8715686274509801],[0.6666666666666666,0,-0.47719298245614045]]},{"nodes":[[],[2,2]]},{"nodes":[[0,0.1],[1.3333333333333333,0.30000000000000004]]},{"nodes":[[],[1.3333333333333333]]},{"nodes":[[0,0,0,0,0.07564543093234954,0.8647058823529409],[1.3333333333333333,1]]},{"nodes":[[],[0.3333333333333333,0.333],[0.3333333333333333,0,0,0,0.04050107306929012,0.096078431372549],[0.5833333333333333,0.30000000000000004,-0.10502788587794674,-0.054901960784313704],[1.3333333333333333]],"fxs":[{"def":"repeat","params":{"interval":0.2499999999999999},"time":0.3333333333333333,"length":1}]},{"nodes":[[0,0,0,0,0.041253263707571805],[0.1,0.472549019607836,-0.044516971279373374,-0.2333333333333331,0.037233176309202774,0.19515571003904697],[1.3333333333333333,1,-1.2945169712793734]]},{"nodes":[[0,0,0,0,0.1],[0.8,0.9,-0.10634811016391839,-0.09574850838471399,0.10634811016391839,0.09574850838471399],[1,1,-0.034837955875665044,-0.008249475331448328]]},{"nodes":[[0,1,0,0,0.08905168734696595,-0.6204705716763121],[0.8,0.1,-0.3657976094933656,0.05238364149449456,0.3657976094933656,-0.05238364149449456],[4,0,-0.5779474714155504]]},{"nodes":[[0,0,0,0,0.33333333333333337],[0.6335509138381202,0.1588235294117648,-0.0296357295978042,-0.12604773105452508,0.0296357295978042,0.12604773105452508],[0.7000000000000001,0.7549019607843139,-0.02819843342036554,-0.09607843137254903,0.02819843342036554,0.09607843137254903],[1.563751087902524,0.9519607843137257,-0.20443864229765013,-0.02745098039215686,0.20443864229765013,0.02745098039215686],[4,1,-0.5779474714155504]]},{"nodes":[[0,0,0,0,0.3154046997389034],[1.3333333333333333,1,-0.29908616187989556]]},{"nodes":[[0,0,0,0,0.1],[1,0,-0.1]]},{"nodes":[[],[1.3333333333333333,1]]},{"nodes":[[0,1,0,0,0.08905168734696595,-0.6204705716763121],[4,0,-3.146485330423383]]},{"nodes":[[0,1,0,0,0.15000000000000002],[0.25,1,-0.1,0,0.047780678851174936],[0.3333333333333333,0,-0.006527415143603133,0.3068670573880632,0.04083550913838122,0.1415436161688415],[0.4601827676240209,0,-0.031462140992167105,0.14076447719138005,0.031462140992167105,0.08154620354285587],[0.5515665796344648,0,-0.024934725848563967,0.05959145643516391,0.03472584856396867,0.040773101771427935],[0.6364229765013054,0,-0.024934725848563963,0.02509113955164797],[1,0,0,0,0.35333333333333333],[2.333333333333333,1,-0.3643603133159269,0,0.1]]},{"nodes":[[0,0,0,0,0.3317232375979112],[2,1,-1.3746781892076712]]},{"nodes":[[0,0,0,0,0.28276762402088773],[2.6666666666666665,1,-0.4673674842468357]]}],"channels":[["EnvironmentMap/accumulate",{"items":[{"value":0.1}]}],["Glitch/amp",{"items":[{},{"time":42.666666666666664,"length":1,"curve":0},{"time":45.33333333333333,"length":1,"curve":0},{"time":48,"length":1,"curve":0},{"time":50.666666666666664,"length":1,"curve":0},{"time":53.33333333333333,"length":1,"curve":0},{"time":56,"length":1,"curve":0},{"time":58.666666666666664,"length":1,"curve":0},{"time":61.33333333333333,"length":1,"curve":0},{"time":64,"length":1,"curve":0},{"time":66.66666666666666,"length":1,"curve":0},{"time":69.33333333333333,"length":1,"curve":0},{"time":72,"length":1,"curve":0},{"time":74.66666666666666,"length":1,"curve":0},{"time":77.33333333333333,"length":1,"curve":0},{"time":80,"length":1,"curve":0},{"time":82.66666666666666,"length":1,"curve":0},{"time":256}]}],["PixelSorter/amp",{"items":[{},{"time":42.666666666666664,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":45.33333333333333,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":48,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":50.666666666666664,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":53.33333333333333,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":56,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":58.666666666666664,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":61.33333333333333,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":64,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":66.66666666666666,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":69.33333333333333,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":72,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":74.66666666666666,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":77.33333333333333,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":80,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":82.66666666666666,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975}]}],["Serial/enable",{"items":[{},{"time":86.66666666666666,"length":1.3333333333333428},{"time":89.33333333333333,"length":1.3333333333333428},{"time":92,"length":1.3333333333333428},{"time":94.66666666666666,"length":1.3333333333333428},{"time":97.33333333333333,"length":1.3333333333333428},{"time":100,"length":1.3333333333333428},{"time":102.66666666666666,"length":1.3333333333333428},{"time":105.33333333333333,"length":1.3333333333333428}]}],["LightFirst/active",{"items":[{"length":106.66666666666666}]}],["Condition/active",{"items":[{"length":42.666666666666664}]}],["Cube/active",{"items":[{"length":42.666666666666664}]}],["Sync/first/clap",{"items":[{},{"time":22.333333333333332,"length":1.3333333333333321,"curve":19},{"time":23.666666666666664,"length":1.3333333333333321,"value":1,"curve":19},{"time":24.999999999999996,"length":1.3333333333333321,"value":2,"curve":19},{"time":26.33333333333333,"length":1.3333333333333321,"value":3,"curve":19},{"time":27.66666666666666,"length":1.3333333333333321,"value":4,"curve":19},{"time":28.999999999999993,"length":1.3333333333333321,"value":5,"curve":19},{"time":30.333333333333325,"length":1.3333333333333321,"value":6,"curve":19},{"time":31.666666666666657,"length":1.3333333333333321,"value":7,"curve":19},{"time":32.999999999999986,"length":1.3333333333333321,"value":8,"curve":19},{"time":34.333333333333314,"length":1.3333333333333321,"value":9,"curve":19},{"time":35.66666666666664,"length":1.3333333333333321,"value":10,"curve":19},{"time":36.99999999999997,"length":1.3333333333333321,"value":11,"curve":19}]}],["Condition/phaseWidth",{"items":[{"value":0.1},{"time":22.333333333333332,"length":20.333333333333332,"value":0.1,"curve":20,"speed":0.049180327868852465,"amp":0.9}]}],["LightPink/active",{"items":[{},{"time":42.666666666666664,"length":42.666666666666664}]}],["Wobbleball/active",{"items":[{},{"time":42.666666666666664,"length":42.666666666666664}]}],["SufferTexts/active",{"items":[{},{"time":42.666666666666664,"length":42.666666666666664}]}],["sufferText/push",{"items":[{"time":42.666666666666664},{"time":45.33333333333333,"value":1},{"time":48,"value":2},{"time":50.666666666666664,"value":3},{"time":53.33333333333333,"value":4},{"time":56,"value":5},{"time":58.666666666666664,"value":6},{"time":61.33333333333333,"value":7},{"time":64,"value":8},{"time":66.66666666666666,"value":9},{"time":69.33333333333333,"value":10},{"time":72,"value":11},{"time":74.66666666666666,"value":12},{"time":77.33333333333333,"value":13},{"time":80,"value":14},{"time":82.66666666666666,"value":15}]}],["IFSPistons/active",{"items":[{},{"time":42.666666666666664,"length":42.666666666666664}]}],["IFSPistons/group0/rot",{"items":[{},{"time":43.33333333333333,"length":2,"curve":28},{"time":48.666666666666664,"length":2,"value":1,"curve":28},{"time":54,"length":2,"value":2,"curve":28},{"time":59.33333333333333,"length":2,"value":3,"curve":28},{"time":64.66666666666666,"length":2,"value":4,"curve":28},{"time":70,"length":2,"value":5,"curve":28},{"time":75.33333333333333,"length":2,"value":6,"curve":28},{"time":80.66666666666666,"length":2,"value":7.319482115535903,"curve":28,"amp":0.6805178844640967}]}],["IFSPistons/group1/rot",{"items":[{},{"time":46,"length":2,"curve":28},{"time":51.33333333333333,"length":2,"value":1,"curve":28},{"time":56.666666666666664,"length":2,"value":2,"curve":28},{"time":62,"length":2,"value":3,"curve":28},{"time":67.33333333333333,"length":2,"value":4,"curve":28},{"time":72.66666666666666,"length":2,"value":5,"curve":28},{"time":78,"length":2,"value":6,"curve":28},{"time":83.33333333333333,"length":2,"value":7,"curve":28}]}],["IFSPistons/group0/pos",{"items":[{"value":3},{"time":42.33333333333333,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":47.666666666666664,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":53,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":58.33333333333333,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":63.7,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":69,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":74.33333333333333,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":79.66666666666666,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5}]}],["IFSPistons/group1/pos",{"items":[{"value":3},{"time":45,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":50.33333333333333,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":55.666666666666664,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":61,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":66.33333333333333,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":71.66666666666666,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":77,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":82.33333333333333,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5}]}],["Music/NEURO_TIME",{"items":[{},{"time":42.666666666666664,"length":10.666666666666664,"curve":2},{"time":53.33333333333333,"length":8.666666666666671,"curve":2},{"time":62,"length":1.999999999999993,"curve":9},{"time":63.99999999999999,"length":10.666666666666664,"curve":2},{"time":74.66666666666666,"length":8.666666666666671,"curve":2},{"time":83.33333333333333,"length":1.999999999999993,"curve":9},{"time":85.33333333333331,"length":1.3333333333333428,"curve":14},{"time":86.66666666666666,"length":1.3333333333333286,"curve":18},{"time":87.99999999999999,"length":1.3333333333333428,"curve":14},{"time":89.33333333333333,"length":1.3333333333333286,"curve":18},{"time":90.66666666666666,"length":1.3333333333333428,"curve":14},{"time":92,"length":1.3333333333333286,"curve":18},{"time":93.33333333333333,"length":1.3333333333333428,"curve":14},{"time":94.66666666666667,"length":1.3333333333333286,"curve":18},{"time":96,"length":1.3333333333333428,"curve":14},{"time":97.33333333333334,"length":1.3333333333333144,"curve":18},{"time":98.66666666666666,"length":1.3333333333333428,"curve":14},{"time":100,"length":1.3333333333333286,"curve":18},{"time":101.33333333333333,"length":1.3333333333333428,"curve":14},{"time":102.66666666666667,"length":1.3333333333333286,"curve":18},{"time":104,"length":1.3333333333333428,"curve":14},{"time":105.33333333333334,"length":1.3333333333333286,"curve":18}]}],["Music/NEURO_DETUNE",{"items":[{},{"time":42.666666666666664,"length":10.666666666666664,"curve":3},{"time":53.33333333333333,"length":8.666666666666671,"curve":3},{"time":62,"length":1.999999999999993,"curve":10},{"time":63.99999999999999,"length":10.666666666666664,"curve":3},{"time":74.66666666666666,"length":8.666666666666671,"curve":3},{"time":83.33333333333333,"length":1.999999999999993,"curve":10},{"time":85.33333333333333,"length":1.3333333333333286,"curve":15},{"time":88,"length":1.3333333333333286,"curve":15},{"time":90.66666666666666,"length":1.3333333333333286,"curve":15},{"time":93.33333333333333,"length":1.3333333333333286,"curve":15},{"time":96,"length":1.3333333333333286,"curve":15},{"time":98.66666666666666,"length":1.3333333333333286,"curve":15},{"time":101.33333333333333,"length":1.3333333333333286,"curve":15},{"time":104,"length":1.3333333333333286,"curve":15}]}],["Music/NEURO_DETUNE_PHASE",{"items":[{},{"time":42.666666666666664,"length":10.666666666666664,"curve":8},{"time":53.33333333333333,"length":8.666666666666671,"curve":8},{"time":62,"length":1.999999999999993,"curve":11},{"time":63.99999999999999,"length":10.666666666666664,"curve":8},{"time":74.66666666666666,"length":8.666666666666671,"curve":8},{"time":83.33333333333333,"length":1.999999999999993,"curve":11},{"time":85.33333333333333,"length":1.3333333333333428,"curve":16},{"time":88,"length":1.3333333333333428,"curve":16},{"time":90.66666666666666,"length":1.3333333333333428,"curve":16},{"time":93.33333333333333,"length":1.3333333333333428,"curve":16},{"time":96,"length":1.3333333333333428,"curve":16},{"time":98.66666666666666,"length":1.3333333333333428,"curve":16},{"time":101.33333333333333,"length":1.3333333333333428,"curve":16},{"time":104,"length":1.3333333333333428,"curve":16}]}],["Music/NEURO_WUB_AMP",{"items":[{},{"time":42.666666666666664,"length":10.668578038364203,"curve":4},{"time":53.33524470503087,"length":8.664755294969133,"curve":4},{"time":62,"length":2.0038227433950624,"curve":12},{"time":64.00382274339506,"length":10.668578038364203,"curve":4},{"time":74.67240078175926,"length":8.660932551574064,"curve":4},{"time":83.33333333333333,"length":2.0038227433950624,"curve":12},{"time":85.33715607672839,"length":1.3333333333333428,"curve":17},{"time":88,"length":1.3333333333333333,"curve":17},{"time":90.66666666666666,"length":1.3333333333333333,"curve":17},{"time":93.33333333333333,"length":1.3333333333333333,"curve":17},{"time":96,"length":1.3333333333333333,"curve":17},{"time":98.66666666666666,"length":1.3333333333333333,"curve":17},{"time":101.33333333333333,"length":1.3333333333333333,"curve":17},{"time":104,"length":1.3333333333333333,"curve":17}]}],["Music/NEURO_WUB_FREQ",{"items":[{},{"time":42.666666666666664,"length":2,"value":1},{"time":44.666666666666664,"length":0.6666666666666643,"value":0.49999999999999967},{"time":45.33333333333333,"length":0.6666666666666714,"value":1},{"time":46,"length":1.3333333333333286,"value":2},{"time":47.33333333333333,"length":0.6666666666666714,"value":2.5},{"time":48,"length":0.6666666666666643,"value":1},{"time":48.666666666666664,"length":1.3333333333333357,"value":1},{"time":50,"length":0.6666666666666643,"value":2},{"time":50.666666666666664,"length":2,"value":1},{"time":52.666666666666664,"length":0.6666666666666643,"value":2},{"time":53.33333333333333,"length":0.6666666666666714,"value":1},{"time":54,"length":1.3333333333333286,"value":2.1000000000000014},{"time":55.33333333333333,"length":0.6666666666666714,"value":0.5},{"time":56,"length":0.6666666666666643,"value":7},{"time":56.666666666666664,"length":1.3333333333333357,"value":3},{"time":58,"length":0.6666666666666714,"value":1},{"time":58.66666666666667,"length":0.6666666666666714,"value":0.9600000000000006},{"time":59.33333333333334,"length":1.3333333333333215,"value":6},{"time":60.666666666666664,"length":0.6666666666666785,"value":10.840000000000003},{"time":61.33333333333334,"length":0.6666666666666572,"value":1},{"time":62,"length":1.3333333333333428,"value":3.989999999999996},{"time":63.33333333333334,"length":0.6666666666666572,"value":4.109999999999999},{"time":64,"length":2,"value":1},{"time":66,"length":0.6666666666666643,"value":0.49999999999999967},{"time":66.66666666666666,"length":0.6666666666666714,"value":1},{"time":67.33333333333333,"length":1.3333333333333286,"value":2},{"time":68.66666666666666,"length":0.6666666666666714,"value":2.5},{"time":69.33333333333333,"length":0.6666666666666643,"value":1},{"time":70,"length":1.3333333333333357,"value":1},{"time":71.33333333333334,"length":0.6666666666666643,"value":2},{"time":72,"length":2,"value":1},{"time":74,"length":0.6666666666666643,"value":2},{"time":74.66666666666666,"length":0.6666666666666714,"value":1},{"time":75.33333333333333,"length":1.3333333333333286,"value":2.1000000000000014},{"time":76.66666666666666,"length":0.6666666666666714,"value":0.5},{"time":77.33333333333333,"length":0.6666666666666643,"value":7},{"time":78,"length":1.3333333333333357,"value":3},{"time":79.33333333333334,"length":0.6666666666666714,"value":1},{"time":80.00000000000001,"length":0.6666666666666714,"value":0.9600000000000006},{"time":80.66666666666669,"length":1.3333333333333144,"value":6},{"time":82,"length":0.6666666666666856,"value":10.840000000000003},{"time":82.66666666666669,"length":0.6666666666666572,"value":1},{"time":83.33333333333334,"length":1.3333333333333428,"value":3.9899999999999993},{"time":84.66666666666669,"length":0.6666666666666572,"value":4.109999999999999},{"time":85.33333333333334,"length":1.3333333333333144,"value":1},{"time":88,"length":1.3333333333333144,"value":1},{"time":90.66666666666666,"length":1.3333333333333144,"value":1},{"time":93.33333333333333,"length":1.3333333333333144,"value":1},{"time":96,"length":1.3333333333333144,"value":1},{"time":98.66666666666666,"length":1.3333333333333144,"value":1},{"time":101.33333333333333,"length":1.3333333333333144,"value":1},{"time":104,"length":1.3333333333333144,"value":1}]}],["Trails/active",{"items":[{}]}],["Rings/active",{"items":[{},{"time":106.66666666666666,"length":42.666666666666664}]}],["FlickyParticles/active",{"items":[{},{"time":85.33333333333333,"length":1.3333333333333286},{"time":88,"length":1.3333333333333286},{"time":90.66666666666666,"length":1.3333333333333286},{"time":93.33333333333333,"length":1.3333333333333286},{"time":96,"length":1.3333333333333286},{"time":98.66666666666666,"length":1.3333333333333286},{"time":101.33333333333333,"length":1.3333333333333286},{"time":104,"length":1.3333333333333286},{"time":106.66666666666666,"length":5.333333333333343}]}],["SphereParticles/active",{"items":[{},{"time":85.33333333333333,"length":42.666666666666664}]}],["FlashyTerrain/active",{"items":[{},{"time":86.66666666666666,"length":1.3333333333333428},{"time":97.33333333333333,"length":1.3333333333333428}]}],["Camera/pos/x",{"items":[{}]}],["Camera/pos/y",{"items":[{},{"time":97.33333333333333,"value":0.8799999999999999}]}],["Camera/pos/z",{"items":[{}]}],["Camera/rot/r",{"items":[{"length":4,"value":5,"curve":21,"amp":10},{"time":20.666666666666664,"length":4,"value":5,"curve":22,"amp":-2},{"time":37.33333333333333,"length":4,"value":10,"curve":23,"offset":-0.009374586224097481,"speed":0.333922345475263,"amp":-3},{"time":42.666666666666664,"value":5},{"time":45.33333333333333,"value":5.6},{"time":48,"value":3.5400000000000005},{"time":50.666666666666664,"value":6.480000000000007},{"time":53.33333333333333,"value":5},{"time":56,"value":5.6},{"time":58.666666666666664,"value":3.630000000000001},{"time":61.33333333333333,"value":6.600000000000005},{"time":85.33333333333333,"length":1.3333333333333286,"value":5,"curve":21,"speed":3.000000000000011,"amp":5},{"time":88,"length":1.3333333333333286,"value":5,"curve":21,"speed":3.000000000000011,"amp":5},{"time":90.66666666666667,"length":1.3333333333333286,"value":5,"curve":21,"speed":3.000000000000011,"amp":5},{"time":93.33333333333334,"length":1.3333333333333144,"value":5,"curve":21,"speed":3.000000000000011,"amp":5},{"time":96.00000000000001,"length":1.3333333333333144,"value":5,"curve":21,"speed":3.000000000000011,"amp":5},{"time":98.66666666666669,"length":1.3333333333333144,"value":5,"curve":21,"speed":3.000000000000011,"amp":5},{"time":101.33333333333336,"length":1.3333333333333002,"value":5,"curve":21,"speed":3.000000000000011,"amp":5},{"time":104.00000000000003,"length":1.3333333333333002,"value":5,"curve":21,"speed":3.000000000000011,"amp":5}]}],["Camera/rot/t",{"items":[{},{"time":21.333333333333332,"length":5.333333333333332,"curve":23,"speed":0.2499999999999999,"amp":0.30000000000000004},{"time":26.666666666666664,"length":5.333333333333332,"value":1.2000000000000002,"curve":23,"speed":0.2499999999999999,"amp":-0.9},{"time":32,"length":5.333333333333329,"curve":23,"speed":0.2499999999999999,"amp":0.30000000000000004},{"time":37.33333333333333},{"time":42.666666666666664},{"time":45.33333333333333,"value":-0.30999999999999495},{"time":48,"value":0.5200000000000048},{"time":50.666666666666664,"value":-0.029999999999995274},{"time":53.33333333333333,"value":0.5500000000000047},{"time":56,"value":-0.2899999999999953},{"time":58.666666666666664,"value":0.9900000000000047},{"time":61.33333333333333,"value":-0.029999999999995274},{"time":85.33333333333333},{"time":86.66666666666666,"value":0.5700000000000002},{"time":88},{"time":90.66666666666666},{"time":93.33333333333333},{"time":96},{"time":97.33333333333333,"value":-0.32},{"time":98.66666666666666},{"time":101.33333333333333},{"time":104}]}],["Camera/rot/p",{"items":[{},{"time":21.333333333333332,"length":5.333333333333332,"curve":23,"speed":0.2499999999999999,"amp":0.30000000000000004},{"time":26.666666666666664,"value":-0.9999999999999998},{"time":32,"length":5.333333333333329,"curve":23,"speed":0.2499999999999999,"amp":0.30000000000000004},{"time":37.33333333333333},{"time":42.666666666666664,"length":2.6666666666666643,"curve":29},{"time":45.33333333333333,"length":2.6666666666666714,"value":0.5009803921568626,"curve":29},{"time":48,"length":2.6666666666666714,"curve":29},{"time":50.66666666666667,"length":2.6666666666666714,"value":-0.39117647058823524,"curve":29},{"time":53.33333333333334,"length":2.6666666666666714,"value":0.08882352941176483,"curve":29},{"time":56.000000000000014,"length":2.6666666666666714,"value":-1.4311764705882353,"curve":29},{"time":58.666666666666686,"length":2.6666666666666714,"value":-0.47117647058823503,"curve":29},{"time":61.33333333333336,"length":2.6666666666666714,"value":-0.031176470588234743,"curve":29},{"time":85.33333333333333},{"time":86.66666666666666,"length":1.3333333333333428,"curve":25,"amp":6},{"time":88},{"time":90.66666666666666},{"time":93.33333333333333},{"time":96},{"time":97.33333333333333,"length":1.3333333333333428,"curve":25,"amp":6},{"time":98.66666666666667},{"time":101.33333333333333},{"time":104}]}],["Camera/roll",{"items":[{"length":21.333333333333332,"curve":26,"speed":0.1875},{"time":96},{"time":97.33333333333333,"value":-0.26000000000000006},{"time":98.66825555990165}]}],["IFSPistons/undefined/rot",{"items":[]}]],"labels":{"zero":0},"guiSettings":{"snapTimeActive":true,"snapTimeInterval":0.1,"snapValueActive":true,"snapValueInterval":1,"snapBeatActive":true,"bpm":180,"beatOffset":0,"useBeatInGUI":true,"minimizedPrecisionTime":3,"minimizedPrecisionValue":3}} \ No newline at end of file +{"version":"4.1.1","resolution":100,"curves":[{"nodes":[[0,1,0,0,0.16140350877192983],[1,0,-0.47719298245614045]]},{"nodes":[[0,0,0,0,0.1],[0.3747555183012014,1,-0.1,0,0.1],[1.3333333333333333,0,-0.1]]},{"nodes":[[],[0.6666666666666666,1,-0.4560629631300563,-0.1852941176470587],[0.6666666666666666,0,0,0,0.26644908616188,0.1029411764705882],[2,1.1900000000000002,-0.1],[2,0.00686274509803933,0,0,0.10652741514360319],[2.6666666666666665,0.7000000000000001],[2.6666666666666665,0,0,0,0.1391644908616188,0.5215686274509802],[3.333333333333333,0.9,-0.5014360313315928,-0.22647058823529403],[3.333333333333333,0,0,0,0.3974946346535474,0.10043744264185422],[4.666666666666666,1.2000000000000002,0,0,0.1],[4.666666666666666],[5.333333333333333,0.7000000000000001,-0.24079400848586707,-0.49736814906842436],[5.333333333333333],[6,0.8,-0.4356422056174482,-0.17156862745098037],[6,0,0,0,0.32852235276081576,0.05490196078431372],[7.333333333333333,1.1441176470588237,-0.1,0,0.1],[7.333333333333333],[8,0.3333],[8,0,0,0,0.08806743643105143,0.4254901960784307],[8.666666666666666,0.9,-0.3995834676293276,-0.08230605476940031],[8.666666666666666],[9.4,1.1,-0.2785205844025618,-0.17156862745098012,0.2785205844025618,0.17156862745098012],[10,1.3],[10],[10.666666666666666,0.6000000000000001,-0.11225401796276425,-0.5783350570563074]],"fxs":[{"def":"repeat","params":{"interval":0.2299999999999996},"time":7.333333333333333,"length":0.6666666666666667}]},{"nodes":[[0,0,0,0,0.12284595300261082,0.061764705882352944],[0.6666666666666666,0.4,-0.1],[0.6666666666666666,0.06568627450980391],[2,0.2],[2.236344893790143,0.4,-0.1,0,0.1],[2.6666666666666665,0,-0.34575086532310695,0,0.04271204452939744],[2.769918291305192,0.1,-0.05130523784998782,0,0.09999999999999999],[3.333333333333333,0.1],[3.6666666666666665,0.32774323388394533],[4.666666666666666,0.30000000000000004],[4.666666666666666,0.023323265139934546],[5.333333333333333,0.1],[5.333333333333333],[6,0.30000000000000004],[6,0.02745098039215696,0,0,0.09974597868276715,-0.006845312262542842],[7.333333333333333,0.1,-0.1],[7.333333333333333,0.7000000000000001],[8.666666666666666,0.7000000000000001],[8.666666666666666,1],[10,0.1],[10.666666666666666]]},{"nodes":[[0,0,0,0,0.1],[0.3333333333333333,1,-0.1,0,0.1],[0.6666666666666666,0,-0.1],[1.9166666666666665,1,-1.0007832898172324,0,0.06],[2],[2.025071712633245,1,-0.044516971279373374,0,0.1],[2.1623944411350506,0.5,-0.07221383357420871,0.2738348538091391,0.07221383357420871,-0.2738348538091391],[2.6666666666666665,0,-0.1,0,0.1],[3,1,-0.2864316909347707,0,0.24406085208595923],[3.333333333333333,0,-0.036443741726782705,0.4106336078810942],[3.6666666666666665,0.7544057184393509,-0.08631141286229893,-0.07178801363349067,0.13346814639852406,0.11100980502520727],[4.666666666666666,1,-0.33942558746736295,-0.018347344929083464,0.09208797505724492,-0.3264027483296351],[4.851079899134173,0.30000000000000004,-0.07486057061026631,-0.013179150760383026,0.1],[5.0444017511428605,0.9656862745098039,-0.1,0,0.1],[5.333333333333333,0.044689231228471016,-0.1,0,0.1],[5.666666666666666,1,-0.1,0,0.1],[6,0,-0.1],[7.333333333333333,1,-1.0426547051383652,0,0.1],[7.6000000000000005,0.7000000000000001,-0.1,0,0.1],[8,1],[8,0,-0.1,0,0.1],[8.166666666666666,1,-0.099988538641853,-0.006965859231865531],[8.489362746562259,1,0,0,0.09998887794379856,-0.006861981819672439],[8.666666666666666,0,-0.11262160793957762,0.041182622607896624],[8.9,1,-0.11617352813418727,-0.020588235294117612,0.11617352813418727,0.020588235294117612],[9.04400609908224,0.15784313725490162,-0.0988340957186134,-0.027450980392156817,0.0988340957186134,0.027450980392156817],[9.3,1,-0.09200304954112025,-0.041176470588235224,0.09200304954112025,0.041176470588235224],[9.5,0.2,-0.09449923761471994,-0.06176470588235285,0.09449923761471994,0.06176470588235285],[9.666666666666666,1,-0.08899847522943988,-0.027450980392156817,0.08899847522943988,0.027450980392156817],[10,0.30000000000000004,-0.06149466330303955,-0.06176470588235285,0.06149466330303955,0.06176470588235285],[10,1,-0.1,0,0.1],[10.666666666666666,0.1,-0.1,0,0.1]],"fxs":[{"def":"repeat","params":{"interval":0.2490000000000001},"time":2,"length":0.6666666666666665},{"def":"sine","params":{"amp":0.26,"freq":8.590000000000002,"offset":0},"time":3.934411837854859,"length":0.7322548288118069},{"def":"sine","params":{"amp":0.4400000000000004,"freq":5.889999999999998,"offset":0},"time":10.234266741175261,"length":0.4323999254914046},{"def":"hermitePatch","params":{},"time":3.821100533282267,"length":0.12610951070520438,"row":1},{"def":"hermitePatch","params":{},"time":10.18270758125172,"length":0.09198590579094379,"row":1}]},{"nodes":[[],[0.5,0.5,0,0,0.3072250626170559,0.32683448369273865],[1.3333333333333333,1.5]]},{"nodes":[[0,0.2,0,0,0.18674781789871728,2.609799325705191],[0.6666666666666666,0.1,-0.3546547911950566,0.44607843137254866]]},{"nodes":[[0,0.15115889256979576,0,0,0.1],[1.3333333333333333,0.7344636184844164,-0.8192982456140352,-0.01372549019607843]],"fxs":[{"def":"sine","params":{"amp":0.42000000000000004,"freq":9.43,"offset":0},"time":0.5833333333333333,"length":0.75},{"def":"hermitePatch","params":{},"time":0.5,"length":0.16666666666666663,"row":1}]},{"nodes":[[0,0,0,0,0.1],[0.6666666666666666,1,-0.1],[0.6666666666666666,0.04000000000000001],[2,0.019999999999999997],[2,0.4],[2.6666666666666665],[3.333333333333333,0.2,-0.1],[3.333333333333333,0.5],[4.666666666666666,0.6000000000000001],[4.666666666666666,0.059594068084455554],[5.333333333333333],[6,0.1],[7.333333333333333,0,-1.3219093627620064,-0.061764705882352944],[8],[8,0.8],[10,0.8],[10,0.1],[10.666666666666666]]},{"nodes":[[0,0,0,0,0.11631853785900784,0.15784313725490196],[0.3333333333333333,0.2,-0.1,-0.06862745098039215],[0.3333333333333333,0,0,0,0.10652741514360313,0.034313725490196074],[0.6257615317667536,0.4,-0.035197899213743125,-0.1178437887562426,0.05762038784328031,0.19291505927163513],[1.5833333333333333,1.6588235294117648,-0.14423846823324632,-0.08235294117647059],[1.5833333333333333,0,0,0,0.0706266318537859,0.12352941176470589],[1.8333333333333333,0.6000000000000001,-0.07923141560987097,-0.16655319476142408,0.05223508415950609,0.10980392156862741],[2,0.8,-0.07118673688066018,-0.08235294117647059]]},{"nodes":[[0,0.7000000000000001,0,0,0.14895561357702347,-0.7343137254901958],[0.6666666666666666,0.01999999999999999,-0.07958650842810296,0.0005266470222471706,0.7602446192333546,-0.005030759268204068],[1.75,0.2,-0.175065274151436,-0.0480392156862745],[2,1,-0.1]]},{"nodes":[[0,0.264705882352941,0,0,0.2664490861618798,-0.3705882352941175],[1.75,0,-0.1,0,0.1],[2,1,-0.1]]},{"nodes":[[0,0,0,0,0.1],[0.3333333333333333,0.9460784313725474,-0.1,0,0.1],[1.3333333333333333,0.3627450980392144,-0.11276290315437737,0.31798356313506776,0.058202350589290165,-0.16412659044332573],[1.6666666666666665,1,-0.1,0,0.1],[1.7304177545691903,0.1,-0.1,0,0.1],[2,1.4000000000000001,-0.05099116999738633,-0.5930547707442783]],"fxs":[{"def":"sine","params":{"amp":0.3999999999999999,"freq":17.779999999999987,"offset":0},"time":0.6103133159268926,"length":0.7230200174064406},{"def":"hermitePatch","params":{},"time":0.5580939947780674,"length":0.08289817232376029,"row":1},{"def":"hermitePatch","params":{},"time":1.2836814621409922,"length":0.11631853785900792,"row":1}]},{"nodes":[[0,1,0,0,0.06843643544269563,-0.8715686274509801],[0.6666666666666666,0,-0.47719298245614045]]},{"nodes":[[],[2,2]]},{"nodes":[[0,0.1],[1.3333333333333333,0.30000000000000004]]},{"nodes":[[],[1.3333333333333333]]},{"nodes":[[0,0,0,0,0.07564543093234954,0.8647058823529409],[1.3333333333333333,1]]},{"nodes":[[],[0.3333333333333333,0.333],[0.3333333333333333,0,0,0,0.04050107306929012,0.096078431372549],[0.5833333333333333,0.30000000000000004,-0.10502788587794674,-0.054901960784313704],[1.3333333333333333]],"fxs":[{"def":"repeat","params":{"interval":0.2499999999999999},"time":0.3333333333333333,"length":1}]},{"nodes":[[0,0,0,0,0.041253263707571805],[0.1,0.472549019607836,-0.044516971279373374,-0.2333333333333331,0.037233176309202774,0.19515571003904697],[1.3333333333333333,1,-1.2945169712793734]]},{"nodes":[[0,0,0,0,0.1],[0.8,0.9,-0.10634811016391839,-0.09574850838471399,0.10634811016391839,0.09574850838471399],[1,1,-0.034837955875665044,-0.008249475331448328]]},{"nodes":[[0,1,0,0,0.08905168734696595,-0.6204705716763121],[0.8,0.1,-0.3657976094933656,0.05238364149449456,0.3657976094933656,-0.05238364149449456],[4,0,-0.5779474714155504]]},{"nodes":[[0,0,0,0,0.33333333333333337],[0.6335509138381202,0.1588235294117648,-0.0296357295978042,-0.12604773105452508,0.0296357295978042,0.12604773105452508],[0.7000000000000001,0.7549019607843139,-0.02819843342036554,-0.09607843137254903,0.02819843342036554,0.09607843137254903],[1.563751087902524,0.9519607843137257,-0.20443864229765013,-0.02745098039215686,0.20443864229765013,0.02745098039215686],[4,1,-0.5779474714155504]]},{"nodes":[[0,0,0,0,0.3154046997389034],[1.3333333333333333,1,-0.29908616187989556]]},{"nodes":[[0,0,0,0,0.1],[1,0,-0.1]]},{"nodes":[[],[1.3333333333333333,1]]},{"nodes":[[0,1,0,0,0.08905168734696595,-0.6204705716763121],[4,0,-3.146485330423383]]},{"nodes":[[0,1,0,0,0.15000000000000002],[0.25,1,-0.1,0,0.047780678851174936],[0.3333333333333333,0,-0.006527415143603133,0.3068670573880632,0.04083550913838122,0.1415436161688415],[0.4601827676240209,0,-0.031462140992167105,0.14076447719138005,0.031462140992167105,0.08154620354285587],[0.5515665796344648,0,-0.024934725848563967,0.05959145643516391,0.03472584856396867,0.040773101771427935],[0.6364229765013054,0,-0.024934725848563963,0.02509113955164797],[1,0,0,0,0.35333333333333333],[2.333333333333333,1,-0.3643603133159269,0,0.1]]},{"nodes":[[0,0,0,0,0.3317232375979112],[2,1,-1.3746781892076712]]},{"nodes":[[0,0,0,0,0.28276762402088773],[2.6666666666666665,1,-0.4673674842468357]]}],"channels":[["EnvironmentMap/accumulate",{"items":[{"value":0.1}]}],["Glitch/amp",{"items":[{},{"time":42.666666666666664,"length":1,"curve":0},{"time":45.33333333333333,"length":1,"curve":0},{"time":48,"length":1,"curve":0},{"time":50.666666666666664,"length":1,"curve":0},{"time":53.33333333333333,"length":1,"curve":0},{"time":56,"length":1,"curve":0},{"time":58.666666666666664,"length":1,"curve":0},{"time":61.33333333333333,"length":1,"curve":0},{"time":64,"length":1,"curve":0},{"time":66.66666666666666,"length":1,"curve":0},{"time":69.33333333333333,"length":1,"curve":0},{"time":72,"length":1,"curve":0},{"time":74.66666666666666,"length":1,"curve":0},{"time":77.33333333333333,"length":1,"curve":0},{"time":80,"length":1,"curve":0},{"time":82.66666666666666,"length":1,"curve":0},{"time":256}]}],["PixelSorter/amp",{"items":[{},{"time":42.666666666666664,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":45.33333333333333,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":48,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":50.666666666666664,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":53.33333333333333,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":56,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":58.666666666666664,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":61.33333333333333,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":64,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":66.66666666666666,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":69.33333333333333,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":72,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":74.66666666666666,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":77.33333333333333,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":80,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975},{"time":82.66666666666666,"length":1.3333333333333357,"curve":13,"speed":0.4999999999999975}]}],["Serial/enable",{"items":[{},{"time":86.66666666666666,"length":1.3333333333333428},{"time":89.33333333333333,"length":1.3333333333333428},{"time":92,"length":1.3333333333333428},{"time":94.66666666666666,"length":1.3333333333333428},{"time":97.33333333333333,"length":1.3333333333333428},{"time":100,"length":1.3333333333333428},{"time":102.66666666666666,"length":1.3333333333333428},{"time":105.33333333333333,"length":1.3333333333333428}]}],["LightFirst/active",{"items":[{"length":106.66666666666666}]}],["Condition/active",{"items":[{"length":42.666666666666664}]}],["Cube/active",{"items":[{"length":42.666666666666664}]}],["Sync/first/clap",{"items":[{},{"time":22.333333333333332,"length":1.3333333333333321,"curve":19},{"time":23.666666666666664,"length":1.3333333333333321,"value":1,"curve":19},{"time":24.999999999999996,"length":1.3333333333333321,"value":2,"curve":19},{"time":26.33333333333333,"length":1.3333333333333321,"value":3,"curve":19},{"time":27.66666666666666,"length":1.3333333333333321,"value":4,"curve":19},{"time":28.999999999999993,"length":1.3333333333333321,"value":5,"curve":19},{"time":30.333333333333325,"length":1.3333333333333321,"value":6,"curve":19},{"time":31.666666666666657,"length":1.3333333333333321,"value":7,"curve":19},{"time":32.999999999999986,"length":1.3333333333333321,"value":8,"curve":19},{"time":34.333333333333314,"length":1.3333333333333321,"value":9,"curve":19},{"time":35.66666666666664,"length":1.3333333333333321,"value":10,"curve":19},{"time":36.99999999999997,"length":1.3333333333333321,"value":11,"curve":19}]}],["Condition/phaseWidth",{"items":[{"value":0.1},{"time":22.333333333333332,"length":20.333333333333332,"value":0.1,"curve":20,"speed":0.049180327868852465,"amp":0.9}]}],["LightPink/active",{"items":[{},{"time":42.666666666666664,"length":42.666666666666664}]}],["Wobbleball/active",{"items":[{},{"time":42.666666666666664,"length":42.666666666666664}]}],["SufferTexts/active",{"items":[{},{"time":42.666666666666664,"length":42.666666666666664}]}],["sufferText/push",{"items":[{"time":42.666666666666664},{"time":45.33333333333333,"value":1},{"time":48,"value":2},{"time":50.666666666666664,"value":3},{"time":53.33333333333333,"value":4},{"time":56,"value":5},{"time":58.666666666666664,"value":6},{"time":61.33333333333333,"value":7},{"time":64,"value":8},{"time":66.66666666666666,"value":9},{"time":69.33333333333333,"value":10},{"time":72,"value":11},{"time":74.66666666666666,"value":12},{"time":77.33333333333333,"value":13},{"time":80,"value":14},{"time":82.66666666666666,"value":15}]}],["IFSPistons/active",{"items":[{},{"time":42.666666666666664,"length":42.666666666666664}]}],["IFSPistons/group0/rot",{"items":[{},{"time":43.33333333333333,"length":2,"curve":28},{"time":48.666666666666664,"length":2,"value":1,"curve":28},{"time":54,"length":2,"value":2,"curve":28},{"time":59.33333333333333,"length":2,"value":3,"curve":28},{"time":64.66666666666666,"length":2,"value":4,"curve":28},{"time":70,"length":2,"value":5,"curve":28},{"time":75.33333333333333,"length":2,"value":6,"curve":28},{"time":80.66666666666666,"length":2,"value":7.319482115535903,"curve":28,"amp":0.6805178844640967}]}],["IFSPistons/group1/rot",{"items":[{},{"time":46,"length":2,"curve":28},{"time":51.33333333333333,"length":2,"value":1,"curve":28},{"time":56.666666666666664,"length":2,"value":2,"curve":28},{"time":62,"length":2,"value":3,"curve":28},{"time":67.33333333333333,"length":2,"value":4,"curve":28},{"time":72.66666666666666,"length":2,"value":5,"curve":28},{"time":78,"length":2,"value":6,"curve":28},{"time":83.33333333333333,"length":2,"value":7,"curve":28}]}],["IFSPistons/group0/pos",{"items":[{"value":3},{"time":42.33333333333333,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":47.666666666666664,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":53,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":58.33333333333333,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":63.7,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":69,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":74.33333333333333,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":79.66666666666666,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5}]}],["IFSPistons/group1/pos",{"items":[{"value":3},{"time":45,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":50.33333333333333,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":55.666666666666664,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":61,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":66.33333333333333,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":71.66666666666666,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":77,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5},{"time":82.33333333333333,"length":2.3333333333333357,"value":1.5,"curve":27,"amp":1.5}]}],["Music/NEURO_TIME",{"items":[{},{"time":42.666666666666664,"length":10.666666666666664,"curve":2},{"time":53.33333333333333,"length":8.666666666666671,"curve":2},{"time":62,"length":1.999999999999993,"curve":9},{"time":63.99999999999999,"length":10.666666666666664,"curve":2},{"time":74.66666666666666,"length":8.666666666666671,"curve":2},{"time":83.33333333333333,"length":1.999999999999993,"curve":9},{"time":85.33333333333331,"length":1.3333333333333428,"curve":14},{"time":86.66666666666666,"length":1.3333333333333286,"curve":18},{"time":87.99999999999999,"length":1.3333333333333428,"curve":14},{"time":89.33333333333333,"length":1.3333333333333286,"curve":18},{"time":90.66666666666666,"length":1.3333333333333428,"curve":14},{"time":92,"length":1.3333333333333286,"curve":18},{"time":93.33333333333333,"length":1.3333333333333428,"curve":14},{"time":94.66666666666667,"length":1.3333333333333286,"curve":18},{"time":96,"length":1.3333333333333428,"curve":14},{"time":97.33333333333334,"length":1.3333333333333144,"curve":18},{"time":98.66666666666666,"length":1.3333333333333428,"curve":14},{"time":100,"length":1.3333333333333286,"curve":18},{"time":101.33333333333333,"length":1.3333333333333428,"curve":14},{"time":102.66666666666667,"length":1.3333333333333286,"curve":18},{"time":104,"length":1.3333333333333428,"curve":14},{"time":105.33333333333334,"length":1.3333333333333286,"curve":18}]}],["Music/NEURO_DETUNE",{"items":[{},{"time":42.666666666666664,"length":10.666666666666664,"curve":3},{"time":53.33333333333333,"length":8.666666666666671,"curve":3},{"time":62,"length":1.999999999999993,"curve":10},{"time":63.99999999999999,"length":10.666666666666664,"curve":3},{"time":74.66666666666666,"length":8.666666666666671,"curve":3},{"time":83.33333333333333,"length":1.999999999999993,"curve":10},{"time":85.33333333333333,"length":1.3333333333333286,"curve":15},{"time":88,"length":1.3333333333333286,"curve":15},{"time":90.66666666666666,"length":1.3333333333333286,"curve":15},{"time":93.33333333333333,"length":1.3333333333333286,"curve":15},{"time":96,"length":1.3333333333333286,"curve":15},{"time":98.66666666666666,"length":1.3333333333333286,"curve":15},{"time":101.33333333333333,"length":1.3333333333333286,"curve":15},{"time":104,"length":1.3333333333333286,"curve":15}]}],["Music/NEURO_DETUNE_PHASE",{"items":[{},{"time":42.666666666666664,"length":10.666666666666664,"curve":8},{"time":53.33333333333333,"length":8.666666666666671,"curve":8},{"time":62,"length":1.999999999999993,"curve":11},{"time":63.99999999999999,"length":10.666666666666664,"curve":8},{"time":74.66666666666666,"length":8.666666666666671,"curve":8},{"time":83.33333333333333,"length":1.999999999999993,"curve":11},{"time":85.33333333333333,"length":1.3333333333333428,"curve":16},{"time":88,"length":1.3333333333333428,"curve":16},{"time":90.66666666666666,"length":1.3333333333333428,"curve":16},{"time":93.33333333333333,"length":1.3333333333333428,"curve":16},{"time":96,"length":1.3333333333333428,"curve":16},{"time":98.66666666666666,"length":1.3333333333333428,"curve":16},{"time":101.33333333333333,"length":1.3333333333333428,"curve":16},{"time":104,"length":1.3333333333333428,"curve":16}]}],["Music/NEURO_WUB_AMP",{"items":[{},{"time":42.666666666666664,"length":10.668578038364203,"curve":4},{"time":53.33524470503087,"length":8.664755294969133,"curve":4},{"time":62,"length":2.0038227433950624,"curve":12},{"time":64.00382274339506,"length":10.668578038364203,"curve":4},{"time":74.67240078175926,"length":8.660932551574064,"curve":4},{"time":83.33333333333333,"length":2.0038227433950624,"curve":12},{"time":85.33715607672839,"length":1.3333333333333428,"curve":17},{"time":88,"length":1.3333333333333333,"curve":17},{"time":90.66666666666666,"length":1.3333333333333333,"curve":17},{"time":93.33333333333333,"length":1.3333333333333333,"curve":17},{"time":96,"length":1.3333333333333333,"curve":17},{"time":98.66666666666666,"length":1.3333333333333333,"curve":17},{"time":101.33333333333333,"length":1.3333333333333333,"curve":17},{"time":104,"length":1.3333333333333333,"curve":17}]}],["Music/NEURO_WUB_FREQ",{"items":[{},{"time":42.666666666666664,"length":2,"value":1},{"time":44.666666666666664,"length":0.6666666666666643,"value":0.49999999999999967},{"time":45.33333333333333,"length":0.6666666666666714,"value":1},{"time":46,"length":1.3333333333333286,"value":2},{"time":47.33333333333333,"length":0.6666666666666714,"value":2.5},{"time":48,"length":0.6666666666666643,"value":1},{"time":48.666666666666664,"length":1.3333333333333357,"value":1},{"time":50,"length":0.6666666666666643,"value":2},{"time":50.666666666666664,"length":2,"value":1},{"time":52.666666666666664,"length":0.6666666666666643,"value":2},{"time":53.33333333333333,"length":0.6666666666666714,"value":1},{"time":54,"length":1.3333333333333286,"value":2.1000000000000014},{"time":55.33333333333333,"length":0.6666666666666714,"value":0.5},{"time":56,"length":0.6666666666666643,"value":7},{"time":56.666666666666664,"length":1.3333333333333357,"value":3},{"time":58,"length":0.6666666666666714,"value":1},{"time":58.66666666666667,"length":0.6666666666666714,"value":0.9600000000000006},{"time":59.33333333333334,"length":1.3333333333333215,"value":6},{"time":60.666666666666664,"length":0.6666666666666785,"value":10.840000000000003},{"time":61.33333333333334,"length":0.6666666666666572,"value":1},{"time":62,"length":1.3333333333333428,"value":3.989999999999996},{"time":63.33333333333334,"length":0.6666666666666572,"value":4.109999999999999},{"time":64,"length":2,"value":1},{"time":66,"length":0.6666666666666643,"value":0.49999999999999967},{"time":66.66666666666666,"length":0.6666666666666714,"value":1},{"time":67.33333333333333,"length":1.3333333333333286,"value":2},{"time":68.66666666666666,"length":0.6666666666666714,"value":2.5},{"time":69.33333333333333,"length":0.6666666666666643,"value":1},{"time":70,"length":1.3333333333333357,"value":1},{"time":71.33333333333334,"length":0.6666666666666643,"value":2},{"time":72,"length":2,"value":1},{"time":74,"length":0.6666666666666643,"value":2},{"time":74.66666666666666,"length":0.6666666666666714,"value":1},{"time":75.33333333333333,"length":1.3333333333333286,"value":2.1000000000000014},{"time":76.66666666666666,"length":0.6666666666666714,"value":0.5},{"time":77.33333333333333,"length":0.6666666666666643,"value":7},{"time":78,"length":1.3333333333333357,"value":3},{"time":79.33333333333334,"length":0.6666666666666714,"value":1},{"time":80.00000000000001,"length":0.6666666666666714,"value":0.9600000000000006},{"time":80.66666666666669,"length":1.3333333333333144,"value":6},{"time":82,"length":0.6666666666666856,"value":10.840000000000003},{"time":82.66666666666669,"length":0.6666666666666572,"value":1},{"time":83.33333333333334,"length":1.3333333333333428,"value":3.9899999999999993},{"time":84.66666666666669,"length":0.6666666666666572,"value":4.109999999999999},{"time":85.33333333333334,"length":1.3333333333333144,"value":1},{"time":88,"length":1.3333333333333144,"value":1},{"time":90.66666666666666,"length":1.3333333333333144,"value":1},{"time":93.33333333333333,"length":1.3333333333333144,"value":1},{"time":96,"length":1.3333333333333144,"value":1},{"time":98.66666666666666,"length":1.3333333333333144,"value":1},{"time":101.33333333333333,"length":1.3333333333333144,"value":1},{"time":104,"length":1.3333333333333144,"value":1}]}],["Trails/active",{"items":[{}]}],["Rings/active",{"items":[{},{"time":106.66666666666666,"length":42.666666666666664}]}],["FlickyParticles/active",{"items":[{},{"time":42.666666666666664,"length":42.666666666666664},{"time":85.33333333333333,"length":1.3333333333333286},{"time":88,"length":1.3333333333333286},{"time":90.66666666666666,"length":1.3333333333333286},{"time":93.33333333333333,"length":1.3333333333333286},{"time":96,"length":1.3333333333333286},{"time":98.66666666666666,"length":1.3333333333333286},{"time":101.33333333333333,"length":1.3333333333333286},{"time":104,"length":1.3333333333333286},{"time":106.66666666666666,"length":5.333333333333343}]}],["SphereParticles/active",{"items":[{},{"time":85.33333333333333,"length":42.666666666666664}]}],["FlashyTerrain/active",{"items":[{},{"time":86.66666666666666,"length":1.3333333333333428},{"time":97.33333333333333,"length":1.3333333333333428}]}],["Camera/pos/x",{"items":[{}]}],["Camera/pos/y",{"items":[{},{"time":97.33333333333333,"value":0.8799999999999999}]}],["Camera/pos/z",{"items":[{}]}],["Camera/rot/r",{"items":[{"length":4,"value":5,"curve":21,"amp":10},{"time":20.700000000000003,"length":4,"value":5,"curve":22,"amp":-2},{"time":36.666666666666664,"length":4,"value":3,"curve":22,"amp":2},{"time":42.666666666666664,"value":5},{"time":45.33333333333333,"value":5.6},{"time":48,"value":3.5400000000000005},{"time":50.666666666666664,"value":6.480000000000007},{"time":53.33333333333333,"value":5},{"time":56,"value":5.6},{"time":58.666666666666664,"value":3.630000000000001},{"time":61.33333333333333,"value":6.600000000000005},{"time":85.33333333333333,"length":1.3333333333333286,"value":5,"curve":21,"speed":3.000000000000011,"amp":5},{"time":88,"length":1.3333333333333286,"value":5,"curve":21,"speed":3.000000000000011,"amp":5},{"time":90.66666666666667,"length":1.3333333333333286,"value":5,"curve":21,"speed":3.000000000000011,"amp":5},{"time":93.33333333333334,"length":1.3333333333333144,"value":5,"curve":21,"speed":3.000000000000011,"amp":5},{"time":96.00000000000001,"length":1.3333333333333144,"value":5,"curve":21,"speed":3.000000000000011,"amp":5},{"time":98.66666666666669,"length":1.3333333333333144,"value":5,"curve":21,"speed":3.000000000000011,"amp":5},{"time":101.33333333333336,"length":1.3333333333333002,"value":5,"curve":21,"speed":3.000000000000011,"amp":5},{"time":104.00000000000003,"length":1.3333333333333002,"value":5,"curve":21,"speed":3.000000000000011,"amp":5}]}],["Camera/rot/t",{"items":[{},{"time":21.333333333333332,"length":5.333333333333332,"curve":23,"speed":0.2499999999999999,"amp":0.30000000000000004},{"time":26.666666666666664,"length":5.333333333333332,"value":1.2000000000000002,"curve":23,"speed":0.2499999999999999,"amp":-0.9},{"time":32,"length":5.333333333333329,"value":-0.3,"curve":23,"speed":0.2499999999999999,"amp":0.30000000000000004},{"time":42.666666666666664},{"time":45.33333333333333,"value":-0.30999999999999495},{"time":48,"value":0.5200000000000048},{"time":50.666666666666664,"value":-0.029999999999995274},{"time":53.33333333333333,"value":0.5500000000000047},{"time":56,"value":-0.2899999999999953},{"time":58.666666666666664,"value":0.9900000000000047},{"time":61.33333333333333,"value":-0.029999999999995274},{"time":85.33333333333333},{"time":86.66666666666666,"value":0.5700000000000002},{"time":88},{"time":90.66666666666666},{"time":93.33333333333333},{"time":96},{"time":97.33333333333333,"value":-0.32},{"time":98.66666666666666},{"time":101.33333333333333},{"time":104}]}],["Camera/rot/p",{"items":[{},{"time":21.333333333333332,"length":5.333333333333332,"curve":23,"speed":0.2499999999999999,"amp":0.30000000000000004},{"time":26.666666666666664,"value":-0.9999999999999998},{"time":32,"length":5.333333333333329,"value":-0.3,"curve":23,"speed":0.2499999999999999,"amp":0.30000000000000004},{"time":42.666666666666664,"length":2.6666666666666643,"curve":29},{"time":45.33333333333333,"length":2.6666666666666714,"value":0.5009803921568626,"curve":29},{"time":48,"length":2.6666666666666714,"curve":29},{"time":50.66666666666667,"length":2.6666666666666714,"value":-0.39117647058823524,"curve":29},{"time":53.33333333333334,"length":2.6666666666666714,"value":0.08882352941176483,"curve":29},{"time":56.000000000000014,"length":2.6666666666666714,"value":-1.4311764705882353,"curve":29},{"time":58.666666666666686,"length":2.6666666666666714,"value":-0.47117647058823503,"curve":29},{"time":61.33333333333336,"length":2.6666666666666714,"value":-0.031176470588234743,"curve":29},{"time":85.33333333333333},{"time":86.66666666666666,"length":1.3333333333333428,"curve":25,"amp":6},{"time":88},{"time":90.66666666666666},{"time":93.33333333333333},{"time":96},{"time":97.33333333333333,"length":1.3333333333333428,"curve":25,"amp":6},{"time":98.66666666666667},{"time":101.33333333333333},{"time":104}]}],["Camera/roll",{"items":[{"length":21.333333333333332,"curve":26,"speed":0.1875},{"time":96},{"time":97.33333333333333,"value":-0.26000000000000006},{"time":98.66825555990165}]}],["IFSPistons/undefined/rot",{"items":[]}]],"labels":{"zero":0},"guiSettings":{"snapTimeActive":true,"snapTimeInterval":0.1,"snapValueActive":true,"snapValueInterval":1,"snapBeatActive":true,"bpm":180,"beatOffset":0,"useBeatInGUI":true,"minimizedPrecisionTime":3,"minimizedPrecisionValue":3}} \ No newline at end of file diff --git a/src/config.ts b/src/config.ts index e568714..13cbbd9 100644 --- a/src/config.ts +++ b/src/config.ts @@ -6,5 +6,7 @@ export const RESOLUTION = [ 1280, 720 ], MUSIC_BPM = 180, START_POSITION = 36, - MUSIC_BUFFER_LENGTH = 4096, - MUSIC_AUTOMATON_TEXTURE_HEIGHT = 16; + MUSIC_LENGTH = 213, + MUSIC_AUTOMATON_TEXTURE_HEIGHT = 16, + IBLLUT_ITER = 400, + IBLLUT_SIZE = 256; diff --git a/src/entities/IBLLUT.ts b/src/entities/IBLLUT.ts index 5a37732..1adf438 100644 --- a/src/entities/IBLLUT.ts +++ b/src/entities/IBLLUT.ts @@ -1,6 +1,7 @@ import { BufferRenderTarget } from '../heck/BufferRenderTarget'; import { Entity } from '../heck/Entity'; import { GLCatTexture } from '@fms-cat/glcat-ts'; +import { IBLLUT_ITER, IBLLUT_SIZE } from '../config'; import { Lambda } from '../heck/components/Lambda'; import { Material } from '../heck/Material'; import { Quad } from '../heck/components/Quad'; @@ -11,8 +12,6 @@ import { vdc } from '../utils/vdc'; import iblLutFrag from '../shaders/ibl-lut.frag'; import quadVert from '../shaders/quad.vert'; -const IBL_SIZE = 256; - export class IBLLUT { public entity: Entity; @@ -29,13 +28,13 @@ export class IBLLUT { // -- swap ------------------------------------------------------------------------------------- this.swap = new Swap( new BufferRenderTarget( { - width: IBL_SIZE, - height: IBL_SIZE, + width: IBLLUT_SIZE, + height: IBLLUT_SIZE, name: process.env.DEV && 'IBLLUT/swap0', } ), new BufferRenderTarget( { - width: IBL_SIZE, - height: IBL_SIZE, + width: IBLLUT_SIZE, + height: IBLLUT_SIZE, name: process.env.DEV && 'IBLLUT/swap1', } ), ); @@ -64,7 +63,7 @@ export class IBLLUT { samples ++; this.swap.swap(); - if ( samples > 1024 ) { + if ( samples > IBLLUT_ITER ) { this.entity.active = false; } else { material.addUniform( 'samples', '1f', samples ); diff --git a/src/entities/LightEntity.ts b/src/entities/LightEntity.ts index 55a3374..471272c 100644 --- a/src/entities/LightEntity.ts +++ b/src/entities/LightEntity.ts @@ -63,12 +63,6 @@ export class LightEntity extends Entity { this.camera.clear = [ 1.0, 1.0, 1.0, 1.0 ]; this.components.push( this.camera ); - this.shadowMap = new BufferRenderTarget( { - width: options.shadowMapWidth ?? 1024, - height: options.shadowMapHeight ?? 1024, - name: process.env.DEV && `${ options.namePrefix }/shadowMap`, - } ); - swap.swap(); // -- blur ------------------------------------------------------------------------------------- @@ -82,12 +76,15 @@ export class LightEntity extends Entity { material.addUniformTexture( 'sampler0', swap.i.texture ); this.components.push( new Quad( { - target: i === 0 ? swap.o : this.shadowMap, + target: swap.o, material, name: process.env.DEV && `${ options.namePrefix }/quadShadowBlur${ i }`, } ) ); swap.swap(); } + + // -- this is the shadow map ------------------------------------------------------------------- + this.shadowMap = swap.i; } } diff --git a/src/globals/automaton.ts b/src/globals/automaton.ts index 9a25d67..7d0c61d 100644 --- a/src/globals/automaton.ts +++ b/src/globals/automaton.ts @@ -1,9 +1,9 @@ import { Automaton } from '@fms-cat/automaton'; import { AutomatonWithGUI } from '@fms-cat/automaton-with-gui'; +import { Music } from '../music/Music'; import { fxDefinitions } from '../automaton-fxs/fxDefinitions'; import { getDivAutomaton } from './dom'; import automatonData from '../automaton.json'; -import type { Music } from '../Music'; export const automaton = ( () => { if ( process.env.DEV ) { @@ -13,7 +13,7 @@ export const automaton = ( () => { automatonData, { gui: getDivAutomaton(), - isPlaying: true, + isPlaying: false, fxDefinitions, }, ); diff --git a/src/globals/music.ts b/src/globals/music.ts index a7318a8..2ee0d9b 100644 --- a/src/globals/music.ts +++ b/src/globals/music.ts @@ -1,7 +1,9 @@ -import { Music } from '../Music'; +import { Music } from '../music/Music'; +import { MusicOffline } from '../music/MusicOffline'; +import { MusicRealtime } from '../music/MusicRealtime'; import { automatonSetupMusic } from './automaton'; -import { glCat } from './canvas'; export const audio = new AudioContext(); -export const music = new Music( glCat, audio ); +// export const music: Music = new MusicRealtime(); +export const music: Music = new MusicOffline(); automatonSetupMusic( music ); diff --git a/src/main.ts b/src/main.ts index 1d67712..5aa820e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -23,26 +23,12 @@ if ( process.env.DEV ) { canvas.style.margin = 'auto'; canvas.style.maxWidth = '100%'; canvas.style.maxHeight = '100%'; - - music.isPlaying = true; - music.time = START_POSITION; } else { canvas.style.position = 'fixed'; canvas.style.left = '0'; canvas.style.top = '0'; document.body.style.width = canvas.style.width = '100%'; document.body.style.height = canvas.style.height = '100%'; - - const button = document.createElement( 'a' ); - document.body.appendChild( button ); - button.innerHTML = 'click me!'; - - button.onclick = () => { - document.body.appendChild( canvas ); - music.isPlaying = true; - music.time = START_POSITION; - document.body.requestFullscreen(); - }; } // -- keyboards ------------------------------------------------------------------------------------ @@ -85,3 +71,24 @@ if ( process.env.DEV ) { console.info( Component.nameMap ); console.info( BufferRenderTarget.nameMap ); } + +// -- let's gooooo --------------------------------------------------------------------------------- +async function load(): Promise { + await music.prepare(); + + if ( process.env.DEV ) { + music.time = START_POSITION; + ( automaton as AutomatonWithGUI ).play(); + } else { + const button = document.createElement( 'a' ); + document.body.appendChild( button ); + button.innerHTML = 'click me!'; + + button.onclick = () => { + document.body.appendChild( canvas ); + music.isPlaying = true; + document.body.requestFullscreen(); + }; + } +} +load(); diff --git a/src/music/AutomatonManager.ts b/src/music/AutomatonManager.ts new file mode 100644 index 0000000..1493b88 --- /dev/null +++ b/src/music/AutomatonManager.ts @@ -0,0 +1,99 @@ +import { Channel } from '@fms-cat/automaton'; +import { GLCatTexture } from '@fms-cat/glcat-ts'; +import { MUSIC_AUTOMATON_TEXTURE_HEIGHT } from '../config'; +import { Music } from './Music'; +import { audio } from '../globals/music'; +import { automaton } from '../globals/automaton'; +import { gl, glCat } from '../globals/canvas'; +import type { AutomatonWithGUI } from '@fms-cat/automaton-with-gui'; + +/** + * Inject automaton params into music... + */ +export class AutomatonManager { + public texture: GLCatTexture; + public defineString: string; + private __music: Music; + private __ChannelList: Channel[]; + private __array: Float32Array; + + public constructor( music: Music ) { + this.__music = music; + + this.defineString = ''; + this.__ChannelList = []; + + this.__updateAutomatonChannelList(); + + this.__array = new Float32Array( + music.bufferLength * MUSIC_AUTOMATON_TEXTURE_HEIGHT + ); + + this.texture = glCat.createTexture(); + this.texture.textureFilter( gl.NEAREST ); + + // == hot hot hot hot hot ====================================================================== + if ( process.env.DEV ) { + if ( module.hot ) { + module.hot.accept( + [ '../automaton.json' ], + () => { + this.__updateAutomatonChannelList(); + music.recompile?.(); + } + ); + } + + ( automaton as AutomatonWithGUI ).on( 'createChannel', ( { name } ) => { + if ( name.startsWith( 'Music/' ) ) { + this.__updateAutomatonChannelList(); + music.recompile?.(); + } + } ); + + ( automaton as AutomatonWithGUI ).on( 'removeChannel', ( { name } ) => { + if ( name.startsWith( 'Music/' ) ) { + this.__updateAutomatonChannelList(); + music.recompile?.(); + } + } ); + } + } + + public update( time: number ): void { + const bufferLength = this.__music.bufferLength; + + for ( const [ iChannel, channel ] of this.__ChannelList.entries() ) { + for ( let iSample = 0; iSample < bufferLength; iSample ++ ) { + const t = time + iSample / audio.sampleRate; + this.__array[ bufferLength * iChannel + iSample ] = channel.getValue( t ); + } + } + + this.texture.setTextureFromArray( + bufferLength, + MUSIC_AUTOMATON_TEXTURE_HEIGHT, + this.__array, + { + internalformat: gl.R32F, + format: gl.RED, + type: gl.FLOAT, + } + ); + } + + private __updateAutomatonChannelList(): void { + this.__ChannelList = []; + this.defineString = ''; + + for ( const [ channelName, channel ] of automaton.mapNameToChannel.entries() ) { + if ( channelName.startsWith( 'Music/' ) ) { + const key = channelName.substring( 6 ); + const index = this.__ChannelList.length; + const y = ( index + 0.5 ) / MUSIC_AUTOMATON_TEXTURE_HEIGHT; + this.defineString += `const float AUTO_${key}=${y};`; + this.__ChannelList.push( channel ); + } + } + } +} diff --git a/src/music/Music.ts b/src/music/Music.ts new file mode 100644 index 0000000..c5a158e --- /dev/null +++ b/src/music/Music.ts @@ -0,0 +1,178 @@ +import { AutomatonManager } from './AutomatonManager'; +import { GLCatBuffer, GLCatProgram, GLCatTransformFeedback } from '@fms-cat/glcat-ts'; +import { MUSIC_BPM } from '../config'; +import { SamplesManager } from './SamplesManager'; +import { audio } from '../globals/music'; +import { gl, glCat } from '../globals/canvas'; +import { injectCodeToShader } from '../utils/injectCodeToShader'; +import { randomTextureStatic } from '../globals/randomTexture'; +import musicVert from './music.vert'; + +const discardFrag = '#version 300 es\nvoid main(){discard;}'; + +export abstract class Music { + public isPlaying: boolean; + public time: number; + public deltaTime: number; + public readonly bufferLength: number; + + protected __program: GLCatProgram; + protected __samplesManager: SamplesManager; + protected __automatonManager: AutomatonManager; + + private __bufferOff: GLCatBuffer; + private __bufferTransformFeedbacks: [ + GLCatBuffer, + GLCatBuffer, + ]; + private __transformFeedback: GLCatTransformFeedback; + private __prevAudioTime: number; + + public constructor( bufferLength: number ) { + this.isPlaying = false; + this.time = 0.0; + this.deltaTime = 0.0; + this.__prevAudioTime = 0.0; + this.bufferLength = bufferLength; + + // == spicy boys =============================================================================== + this.__samplesManager = new SamplesManager( this ); + this.__automatonManager = new AutomatonManager( this ); + + // == gl ======================================================================================= + const bufferOffArray = new Array( bufferLength ) + .fill( 0 ) + .map( ( _, i ) => i ); + this.__bufferOff = glCat.createBuffer(); + this.__bufferOff.setVertexbuffer( new Float32Array( bufferOffArray ) ); + + this.__bufferTransformFeedbacks = [ + glCat.createBuffer(), + glCat.createBuffer(), + ]; + this.__transformFeedback = glCat.createTransformFeedback(); + + this.__bufferTransformFeedbacks[ 0 ].setVertexbuffer( + bufferLength * 4, + gl.STREAM_READ + ); + + this.__bufferTransformFeedbacks[ 1 ].setVertexbuffer( + bufferLength * 4, + gl.STREAM_READ + ); + + this.__transformFeedback.bindBuffer( 0, this.__bufferTransformFeedbacks[ 0 ] ); + this.__transformFeedback.bindBuffer( 1, this.__bufferTransformFeedbacks[ 1 ] ); + + this.__program = glCat.lazyProgram( + injectCodeToShader( musicVert, this.__automatonManager.defineString ), + discardFrag, + { transformFeedbackVaryings: [ 'outL', 'outR' ] }, + ); + + // == hot hot hot hot hot ====================================================================== + if ( process.env.DEV && module.hot ) { + module.hot.accept( + [ './music.vert' ], + () => { + this.recompile(); + } + ); + } + } + + public async prepare(): Promise { + await this.__samplesManager.loadSamples(); + } + + public async recompile(): Promise { + if ( process.env.DEV ) { + const program = await glCat.lazyProgramAsync( + injectCodeToShader( musicVert, this.__automatonManager.defineString ), + discardFrag, + { transformFeedbackVaryings: [ 'outL', 'outR' ] }, + ).catch( ( error: any ) => { + console.error( error ); + return null; + } ); + + if ( program ) { + this.__program.dispose( true ); + this.__program = program; + } + } + } + + public update(): void { + const now = audio.currentTime; + + if ( this.isPlaying ) { + this.deltaTime = now - this.__prevAudioTime; + this.time += this.deltaTime; + } + + this.__updateImpl(); + + this.__prevAudioTime = now; + } + + protected abstract __updateImpl(): void; + + protected __render( time: number, callback: ( channel: number ) => void ): void { + this.__automatonManager.update( time ); + + const program = this.__program; + + const beatLength = 60.0 / MUSIC_BPM; + const barLength = 240.0 / MUSIC_BPM; + const sixteenBarLength = 3840.0 / MUSIC_BPM; + + program.attribute( 'off', this.__bufferOff, 1 ); + program.uniform( 'bpm', '1f', MUSIC_BPM ); + program.uniform( 'bufferLength', '1f', this.bufferLength ); + program.uniform( '_deltaSample', '1f', 1.0 / audio.sampleRate ); + program.uniform( + 'timeLength', + '4f', + beatLength, + barLength, + sixteenBarLength, + 1E16 + ); + program.uniform( + '_timeHead', + '4f', + time % beatLength, + time % barLength, + time % sixteenBarLength, + time, + ); + + program.uniformTexture( 'samplerRandom', randomTextureStatic.texture ); + program.uniformTexture( 'samplerAutomaton', this.__automatonManager.texture ); + + if ( this.__samplesManager.texture ) { + program.uniformTexture( 'samplerSamples', this.__samplesManager.texture ); + } + + glCat.useProgram( program, () => { + glCat.bindTransformFeedback( this.__transformFeedback, () => { + gl.enable( gl.RASTERIZER_DISCARD ); + gl.beginTransformFeedback( gl.POINTS ); + gl.drawArrays( gl.POINTS, 0, this.bufferLength ); + gl.endTransformFeedback(); + gl.disable( gl.RASTERIZER_DISCARD ); + } ); + } ); + + gl.finish(); // fenceよくわからん + + [ 0, 1 ].map( ( i ) => { + glCat.bindVertexBuffer( + this.__bufferTransformFeedbacks[ i ], + () => callback( i ), + ); + } ); + } +} diff --git a/src/music/MusicOffline.ts b/src/music/MusicOffline.ts new file mode 100644 index 0000000..48905d0 --- /dev/null +++ b/src/music/MusicOffline.ts @@ -0,0 +1,67 @@ +import { MUSIC_LENGTH } from '../config'; +import { Music } from './Music'; +import { audio } from '../globals/music'; +import { gl } from '../globals/canvas'; + +const BUFFER_LENGTH = 16384; + +export class MusicOffline extends Music { + private __buffer: AudioBuffer; + private __currentBufferSource?: AudioBufferSourceNode | null; + + public constructor() { + super( BUFFER_LENGTH ); + + this.__buffer = audio.createBuffer( + 2, + MUSIC_LENGTH * audio.sampleRate, + audio.sampleRate + ); + } + + public async prepare(): Promise { + await super.prepare(); + + let head = 0; + + return new Promise( ( resolve ) => { + const render = (): void => { + const remain = ( MUSIC_LENGTH * audio.sampleRate ) - head; + if ( remain <= 0 ) { + resolve(); + return; + } + + this.__render( head / audio.sampleRate, ( i ) => { + gl.getBufferSubData( + gl.ARRAY_BUFFER, + 0, + this.__buffer.getChannelData( i ), + head, + Math.min( remain, BUFFER_LENGTH ) + ); + } ); + + head += BUFFER_LENGTH; + + setTimeout( render, 1 ); + }; + render(); + } ); + } + + public __updateImpl(): void { + if ( this.isPlaying && this.__currentBufferSource == null ) { + this.__currentBufferSource = audio.createBufferSource(); + this.__currentBufferSource.buffer = this.__buffer; + this.__currentBufferSource.connect( audio.destination ); + + this.__currentBufferSource.start( audio.currentTime, this.time ); + } + + if ( !this.isPlaying && this.__currentBufferSource != null ) { + this.__currentBufferSource.stop( audio.currentTime ); + this.__currentBufferSource = null; + } + } +} diff --git a/src/music/MusicRealtime.ts b/src/music/MusicRealtime.ts new file mode 100644 index 0000000..7b5a72b --- /dev/null +++ b/src/music/MusicRealtime.ts @@ -0,0 +1,55 @@ +import { Music } from './Music'; +import { Pool } from '../utils/Pool'; +import { audio } from '../globals/music'; +import { gl } from '../globals/canvas'; + +const BUFFER_LENGTH = 4096; + +export class MusicRealtime extends Music { + private __bufferPool: Pool; + private __prevBufferSource: AudioBufferSourceNode | null = null; + + public constructor() { + super( BUFFER_LENGTH ); + + this.__bufferPool = new Pool( [ + audio.createBuffer( 2, BUFFER_LENGTH, audio.sampleRate ), + audio.createBuffer( 2, BUFFER_LENGTH, audio.sampleRate ), + ] ); + + // casually calling async function + this.__samplesManager.loadSamples(); + } + + public __updateImpl(): void { + if ( this.isPlaying ) { + const buffer = this.__bufferPool.next(); + const genTime = audio.currentTime; + + if ( this.__program ) { + this.__render( this.time, ( i ) => { + gl.getBufferSubData( + gl.ARRAY_BUFFER, + 0, + buffer.getChannelData( i ), + 0, + BUFFER_LENGTH + ); + } ); + } + + const bufferSource = audio.createBufferSource(); + bufferSource.buffer = buffer; + bufferSource.connect( audio.destination ); + + this.__prevBufferSource?.stop( audio.currentTime ); + bufferSource.start( audio.currentTime, audio.currentTime - genTime ); + this.__prevBufferSource = bufferSource; + } else { + this.deltaTime = 0.0; + + this.__prevBufferSource?.stop( audio.currentTime ); + this.__prevBufferSource = null; + } + } +} diff --git a/src/music/SamplesManager.ts b/src/music/SamplesManager.ts new file mode 100644 index 0000000..8f1632d --- /dev/null +++ b/src/music/SamplesManager.ts @@ -0,0 +1,62 @@ +import { GLCatTexture } from '@fms-cat/glcat-ts'; +import { Music } from './Music'; +import { audio } from '../globals/music'; +import { gl, glCat } from '../globals/canvas'; +import samplesOpus from './samples.opus'; + +export class SamplesManager { + public __music: Music; + + /** + * it can be undefined since it's loaded asynchronously + */ + public texture?: GLCatTexture; + + public constructor( music: Music ) { + this.__music = music; + + // == hot hot hot hot hot ====================================================================== + if ( process.env.DEV ) { + if ( module.hot ) { + module.hot.accept( + [ './samples.opus' ], + async () => { + await this.loadSamples(); + music.recompile?.(); + } + ); + } + } + } + + public async loadSamples(): Promise { + const inputBuffer = await fetch( samplesOpus ).then( ( res ) => res.arrayBuffer() ); + const audioBuffer = await audio.decodeAudioData( inputBuffer ); + + const buffer = new Float32Array( 96000 ); + + const data = audioBuffer.getChannelData( 0 ); + for ( let i = 0; i < audioBuffer.length; i ++ ) { + buffer[ i ] = data[ i ]; + } + + const texture = glCat.createTexture()!; + texture.setTextureFromArray( + 6000, + 16, + buffer, + { + internalformat: gl.R32F, + format: gl.RED, + type: gl.FLOAT, + } + ); + texture.textureFilter( gl.LINEAR ); + + if ( process.env.DEV && this.texture != null ) { + this.texture.dispose(); + } + + this.texture = texture; + } +} diff --git a/src/shaders/music.vert b/src/music/music.vert similarity index 100% rename from src/shaders/music.vert rename to src/music/music.vert diff --git a/src/samples.opus b/src/music/samples.opus similarity index 100% rename from src/samples.opus rename to src/music/samples.opus diff --git a/src/scene.ts b/src/scene.ts index 5a7eeb2..5a02e96 100644 --- a/src/scene.ts +++ b/src/scene.ts @@ -14,6 +14,7 @@ import { FlashyTerrain } from './entities/FlashyTerrain'; import { FlickyParticles } from './entities/FlickyParticles'; import { Glitch } from './entities/Glitch'; import { IBLLUT } from './entities/IBLLUT'; +import { IFSPistons } from './entities/IFSPistons'; import { Lambda } from './heck/components/Lambda'; import { LightEntity } from './entities/LightEntity'; import { PixelSorter } from './entities/PixelSorter'; @@ -162,6 +163,13 @@ if ( process.env.DEV && module.hot ) { } ); } +const replacerIFSPistons = new EntityReplacer( () => new IFSPistons(), 'IFSPistons' ); +if ( process.env.DEV && module.hot ) { + module.hot.accept( './entities/IFSPistons', () => { + replacerIFSPistons.replace(); + } ); +} + // -- things that is not an "object" --------------------------------------------------------------- const swapOptions = { width: canvasRenderTarget.width, @@ -187,7 +195,7 @@ const replacerLightFirst = new EntityReplacer( () => { shadowMapFar: 20.0, namePrefix: process.env.DEV && 'lightFirst', } ); - light.color = [ 1.0, 1.0, 1.0 ]; + light.color = [ 40.0, 40.0, 40.0 ]; light.transform.lookAt( new Vector3( [ -1.0, 2.0, 8.0 ] ) ); return light; }, 'LightFirst' ); @@ -201,7 +209,7 @@ const replacerLightPink = new EntityReplacer( () => { shadowMapFar: 20.0, namePrefix: process.env.DEV && 'lightPink', } ); - light.color = [ 60.0, 1.0, 5.0 ]; + light.color = [ 120.0, 2.0, 10.0 ]; light.transform.lookAt( new Vector3( [ -1.0, 4.0, 4.0 ] ) ); return light; }, 'LightPink' );