├── .eleventy.js ├── .eleventyignore ├── .eslintrc.json ├── .github └── workflows │ ├── ci.yml │ ├── main.yml │ └── playwright.yml ├── .gitignore ├── .prettierrc.json ├── CONTRIBUTORS ├── LICENSE ├── README.md ├── docs ├── README.md ├── abhay-gupta-GSOC-24.md ├── kizjkre-gsoc24.md └── terry-feng-GSoC-2024.md ├── package-lock.json ├── package.json ├── playwright.config.ts ├── postcss.config.js ├── src ├── CONTRIBUTING.md ├── README.md ├── _data │ ├── audioworklet_data.yaml │ ├── build_info.json │ ├── experiments_data.yaml │ ├── footer_data.yaml │ ├── global_data.yaml │ ├── landing_data.yaml │ └── tests_data.yaml ├── _includes │ ├── base.njk │ ├── example-source-code.njk │ ├── footer.njk │ └── header.njk ├── audio-worklet │ ├── basic │ │ ├── audio-worklet-node-options │ │ │ ├── index.njk │ │ │ ├── main.js │ │ │ └── oscillator-processor.js │ │ ├── bit-crusher │ │ │ ├── bit-crusher-processor.js │ │ │ ├── index.njk │ │ │ └── main.js │ │ ├── handling-errors │ │ │ ├── error-processor.js │ │ │ ├── index.njk │ │ │ └── main.js │ │ ├── hello-audio-worklet │ │ │ ├── bypass-processor.js │ │ │ ├── index.njk │ │ │ └── main.js │ │ ├── message-port │ │ │ ├── index.njk │ │ │ ├── main.js │ │ │ └── messenger-processor.js │ │ ├── noise-generator │ │ │ ├── index.njk │ │ │ ├── main.js │ │ │ └── noise-generator.js │ │ ├── one-pole-filter │ │ │ ├── index.njk │ │ │ ├── main.js │ │ │ └── one-pole-processor.js │ │ └── volume-meter │ │ │ ├── index.njk │ │ │ ├── main.js │ │ │ └── volume-meter-processor.js │ ├── design-pattern │ │ ├── lib │ │ │ ├── em-es6-module.js │ │ │ └── wasm-audio-helper.js │ │ ├── shared-buffer │ │ │ ├── coi-serviceworker.js │ │ │ ├── index.njk │ │ │ ├── main.js │ │ │ ├── shared-buffer-worker.js │ │ │ ├── shared-buffer-worklet-node.js │ │ │ └── shared-buffer-worklet-processor.js │ │ ├── wasm-ring-buffer │ │ │ ├── Makefile │ │ │ ├── VariableBufferKernel.cc │ │ │ ├── index.njk │ │ │ ├── main.js │ │ │ ├── ring-buffer-worklet-processor.js │ │ │ └── variable-buffer-kernel.wasmmodule.js │ │ ├── wasm-supersaw │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── index.njk │ │ │ ├── main.js │ │ │ ├── synth-processor.js │ │ │ ├── synth.wasm.js │ │ │ └── synth_src │ │ │ │ ├── BiquadFilter.h │ │ │ │ ├── ChannelContext.h │ │ │ │ ├── DifferentiatedParabola.h │ │ │ │ ├── EnvelopeADSR.h │ │ │ │ ├── LookupTable.h │ │ │ │ ├── PitchToFrequency.cpp │ │ │ │ ├── PitchToFrequency.h │ │ │ │ ├── SawtoothOscillator.h │ │ │ │ ├── SawtoothOscillatorDPW.h │ │ │ │ ├── SimpleVoice.h │ │ │ │ ├── SineOscillator.h │ │ │ │ ├── SquareOscillatorDPW.h │ │ │ │ ├── SynthMark.h │ │ │ │ ├── SynthTools.h │ │ │ │ ├── Synthesizer.h │ │ │ │ ├── UnitGenerator.cpp │ │ │ │ ├── UnitGenerator.h │ │ │ │ ├── VoiceBase.h │ │ │ │ └── synth_bind.cc │ │ └── wasm │ │ │ ├── Makefile │ │ │ ├── SimpleKernel.cc │ │ │ ├── index.njk │ │ │ ├── main.js │ │ │ ├── simple-kernel.wasmmodule.js │ │ │ └── wasm-worklet-processor.js │ ├── free-queue │ │ ├── README.md │ │ ├── examples │ │ │ └── simple-passthrough │ │ │ │ ├── basic-processor.js │ │ │ │ ├── coi-serviceworker.js │ │ │ │ ├── constants.js │ │ │ │ ├── index.njk │ │ │ │ ├── main.js │ │ │ │ └── worker.js │ │ └── src │ │ │ ├── free-queue.js │ │ │ └── interface │ │ │ ├── README.md │ │ │ └── free_queue.h │ ├── index.njk │ └── migration │ │ ├── spn-recorder │ │ ├── README.md │ │ ├── app.js │ │ ├── exporter.mjs │ │ └── index.njk │ │ └── worklet-recorder │ │ ├── README.md │ │ ├── app.js │ │ ├── exporter.mjs │ │ ├── index.njk │ │ └── recording-processor.js ├── demos │ ├── dj │ │ ├── dj.css │ │ ├── dj.js │ │ └── index.html │ ├── mld-drum-sampler │ │ ├── DrumCell.js │ │ ├── README.md │ │ ├── index.njk │ │ ├── main.js │ │ └── samples │ │ │ ├── drum-fx-01.mp3 │ │ │ ├── drum-fx-02.mp3 │ │ │ ├── drum-hh-01.mp3 │ │ │ ├── drum-hh-02.mp3 │ │ │ ├── drum-kd-01.mp3 │ │ │ ├── drum-kd-02.mp3 │ │ │ ├── drum-oh-01.mp3 │ │ │ ├── drum-oh-02.mp3 │ │ │ ├── drum-perc-01.mp3 │ │ │ ├── drum-perc-02.mp3 │ │ │ ├── drum-sd-01.mp3 │ │ │ ├── drum-sd-02.mp3 │ │ │ ├── ir-hall.mp3 │ │ │ └── samples.zip │ ├── panning-reverberation │ │ ├── index.html │ │ ├── lib │ │ │ └── events.js │ │ └── simple.css │ ├── pool │ │ ├── images │ │ │ └── poolballs.png │ │ ├── index.html │ │ ├── o3d-webgl │ │ │ ├── archive_request.js │ │ │ ├── base.js │ │ │ ├── bitmap.js │ │ │ ├── bounding_box.js │ │ │ ├── buffer.js │ │ │ ├── clear_buffer.js │ │ │ ├── client.js │ │ │ ├── draw_context.js │ │ │ ├── draw_element.js │ │ │ ├── draw_list.js │ │ │ ├── draw_pass.js │ │ │ ├── effect.js │ │ │ ├── element.js │ │ │ ├── event.js │ │ │ ├── field.js │ │ │ ├── file_request.js │ │ │ ├── material.js │ │ │ ├── named_object.js │ │ │ ├── named_object_base.js │ │ │ ├── object_base.js │ │ │ ├── pack.js │ │ │ ├── param.js │ │ │ ├── param_object.js │ │ │ ├── primitive.js │ │ │ ├── raw_data.js │ │ │ ├── ray_intersection_info.js │ │ │ ├── render_node.js │ │ │ ├── render_surface.js │ │ │ ├── render_surface_set.js │ │ │ ├── sampler.js │ │ │ ├── shape.js │ │ │ ├── state.js │ │ │ ├── state_set.js │ │ │ ├── stream.js │ │ │ ├── stream_bank.js │ │ │ ├── texture.js │ │ │ ├── transform.js │ │ │ ├── tree_traversal.js │ │ │ ├── types.js │ │ │ └── viewport.js │ │ └── o3djs │ │ │ ├── base.js │ │ │ └── webgl.js │ ├── pwa-audio-recorder │ │ ├── README.md │ │ ├── app.mjs │ │ ├── icons │ │ │ ├── android-chrome-192.png │ │ │ ├── android-chrome-512.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── favicon.png │ │ │ ├── maskable-192.png │ │ │ └── maskable-512.png │ │ ├── index.html │ │ ├── indexeddb-storage.mjs │ │ ├── service-worker.js │ │ ├── site.webmanifest │ │ ├── style.css │ │ └── visualize.mjs │ ├── shiny-drum-machine │ │ ├── drummachine.css │ │ ├── images │ │ │ ├── LED_off.png │ │ │ ├── LED_on.png │ │ │ ├── btn_cancel.png │ │ │ ├── btn_demo1.png │ │ │ ├── btn_demo1_loading.gif │ │ │ ├── btn_demo2.png │ │ │ ├── btn_demo2_loading.gif │ │ │ ├── btn_demo3.png │ │ │ ├── btn_demo3_loading.gif │ │ │ ├── btn_demo4.png │ │ │ ├── btn_demo4_loading.gif │ │ │ ├── btn_demo5.png │ │ │ ├── btn_demo5_loading.gif │ │ │ ├── btn_load.png │ │ │ ├── btn_ok.png │ │ │ ├── btn_play.png │ │ │ ├── btn_play_loading.gif │ │ │ ├── btn_reset.png │ │ │ ├── btn_save.png │ │ │ ├── btn_stop.png │ │ │ ├── button_half.png │ │ │ ├── button_off.png │ │ │ ├── button_on.png │ │ │ ├── drop_arrow.png │ │ │ ├── slider_thumb.png │ │ │ ├── slider_track.png │ │ │ ├── sliderh_thumb.png │ │ │ ├── sliderh_track.png │ │ │ ├── tempo_bg.png │ │ │ ├── tempo_dec.png │ │ │ └── tempo_inc.png │ │ ├── index.html │ │ ├── shiny-drum-machine-audio.js │ │ ├── shiny-drum-machine-data.js │ │ ├── shiny-drum-machine-ui.js │ │ └── shiny-drum-machine.js │ ├── stress-box │ │ ├── assets │ │ │ └── style.css │ │ ├── index.html │ │ ├── js │ │ │ ├── app.js │ │ │ ├── demo-base.js │ │ │ ├── draw-world.js │ │ │ ├── lib.js │ │ │ ├── stack.js │ │ │ ├── top.js │ │ │ └── web-audio.js │ │ └── third-party │ │ │ ├── Box2D_v2.3.1_min.js │ │ │ ├── box2d │ │ │ ├── collision │ │ │ │ ├── ClipVertex.js │ │ │ │ ├── Features.js │ │ │ │ ├── b2AABB.js │ │ │ │ ├── b2Bound.js │ │ │ │ ├── b2BoundValues.js │ │ │ │ ├── b2BroadPhase.js │ │ │ │ ├── b2BufferedPair.js │ │ │ │ ├── b2Collision.js │ │ │ │ ├── b2ContactID.js │ │ │ │ ├── b2ContactPoint.js │ │ │ │ ├── b2Distance.js │ │ │ │ ├── b2Manifold.js │ │ │ │ ├── b2OBB.js │ │ │ │ ├── b2Pair.js │ │ │ │ ├── b2PairCallback.js │ │ │ │ ├── b2PairManager.js │ │ │ │ ├── b2Proxy.js │ │ │ │ └── shapes │ │ │ │ │ ├── b2BoxDef.js │ │ │ │ │ ├── b2CircleDef.js │ │ │ │ │ ├── b2CircleShape.js │ │ │ │ │ ├── b2MassData.js │ │ │ │ │ ├── b2PolyDef.js │ │ │ │ │ ├── b2PolyShape.js │ │ │ │ │ ├── b2Shape.js │ │ │ │ │ └── b2ShapeDef.js │ │ │ ├── common │ │ │ │ ├── b2Settings.js │ │ │ │ └── math │ │ │ │ │ ├── b2Mat22.js │ │ │ │ │ ├── b2Math.js │ │ │ │ │ └── b2Vec2.js │ │ │ └── dynamics │ │ │ │ ├── b2Body.js │ │ │ │ ├── b2BodyDef.js │ │ │ │ ├── b2CollisionFilter.js │ │ │ │ ├── b2ContactManager.js │ │ │ │ ├── b2Island.js │ │ │ │ ├── b2TimeStep.js │ │ │ │ ├── b2World.js │ │ │ │ ├── b2WorldListener.js │ │ │ │ ├── contacts │ │ │ │ ├── b2CircleContact.js │ │ │ │ ├── b2Conservative.js │ │ │ │ ├── b2Contact.js │ │ │ │ ├── b2ContactConstraint.js │ │ │ │ ├── b2ContactConstraintPoint.js │ │ │ │ ├── b2ContactNode.js │ │ │ │ ├── b2ContactRegister.js │ │ │ │ ├── b2ContactSolver.js │ │ │ │ ├── b2NullContact.js │ │ │ │ ├── b2PolyAndCircleContact.js │ │ │ │ └── b2PolyContact.js │ │ │ │ └── joints │ │ │ │ ├── b2DistanceJoint.js │ │ │ │ ├── b2DistanceJointDef.js │ │ │ │ ├── b2GearJoint.js │ │ │ │ ├── b2GearJointDef.js │ │ │ │ ├── b2Jacobian.js │ │ │ │ ├── b2Joint.js │ │ │ │ ├── b2JointDef.js │ │ │ │ ├── b2JointNode.js │ │ │ │ ├── b2MouseJoint.js │ │ │ │ ├── b2MouseJointDef.js │ │ │ │ ├── b2PrismaticJoint.js │ │ │ │ ├── b2PrismaticJointDef.js │ │ │ │ ├── b2PulleyJoint.js │ │ │ │ ├── b2PulleyJointDef.js │ │ │ │ ├── b2RevoluteJoint.js │ │ │ │ └── b2RevoluteJointDef.js │ │ │ └── prototype-1.6.0.2.js │ ├── visualizer │ │ ├── index.html │ │ ├── lib │ │ │ ├── cameracontroller.js │ │ │ ├── events.js │ │ │ ├── matrix4x4.js │ │ │ ├── o3djs │ │ │ │ ├── base.js │ │ │ │ ├── math.js │ │ │ │ ├── particles.js │ │ │ │ ├── quaternions.js │ │ │ │ └── shader.js │ │ │ ├── utils3d.js │ │ │ └── visualizer.js │ │ └── shaders │ │ │ ├── common-vertex.shader │ │ │ ├── frequency-fragment.shader │ │ │ ├── sonogram-fragment.shader │ │ │ ├── sonogram-vertex.shader │ │ │ ├── texture-only.shader │ │ │ └── waveform-fragment.shader │ ├── wavetable-synth-2 │ │ ├── README.md │ │ ├── index.html │ │ ├── layout.html │ │ ├── prototype.html │ │ ├── resources │ │ │ └── sound_combine.py │ │ ├── script │ │ │ ├── BPMDelay.js │ │ │ ├── GlobalEffect.js │ │ │ ├── Note.js │ │ │ ├── Sequencer.js │ │ │ ├── WaveShaper.js │ │ │ ├── WavetableDataSet.js │ │ │ ├── fft.js │ │ │ ├── layout.js │ │ │ ├── main.js │ │ │ └── prototype.js │ │ ├── sound │ │ │ └── matrix-reverb6.wav │ │ ├── style │ │ │ ├── layout.css │ │ │ ├── normalize.css │ │ │ └── style.css │ │ └── ui-components │ │ │ ├── Dropdown.js │ │ │ ├── KnobSimple.js │ │ │ ├── MatrixSequence2D.js │ │ │ ├── ToggleSimple.js │ │ │ └── WavetableView.js │ └── wavetable-synth │ │ ├── images │ │ └── loading.gif │ │ ├── index.html │ │ ├── lib │ │ ├── adsr.js │ │ ├── bpm-delay.js │ │ ├── buffer-loader.js │ │ ├── chorus.js │ │ ├── events.js │ │ ├── fft.js │ │ ├── global-effects.js │ │ ├── granular.js │ │ ├── jungle.js │ │ ├── knob.js │ │ ├── waveshaper.js │ │ ├── wavetable.js │ │ └── wavetable2.js │ │ ├── simple.css │ │ └── wave-tables │ │ ├── 01_Saw │ │ ├── 02_Triangle │ │ ├── 03_Square │ │ ├── 04_Noise │ │ ├── 05_Pulse │ │ ├── 06_Warm_Saw │ │ ├── 07_Warm_Triangle │ │ ├── 08_Warm_Square │ │ ├── 09_Dropped_Saw │ │ ├── 10_Dropped_Square │ │ ├── 11_TB303_Square │ │ ├── Bass │ │ ├── Bass_Amp360 │ │ ├── Bass_Fuzz │ │ ├── Bass_Fuzz_ 2 │ │ ├── Bass_Sub_Dub │ │ ├── Bass_Sub_Dub_2 │ │ ├── Brass │ │ ├── Brit_Blues │ │ ├── Brit_Blues_Driven │ │ ├── Buzzy_1 │ │ ├── Buzzy_2 │ │ ├── Celeste │ │ ├── Chorus_Strings │ │ ├── Dissonant Piano │ │ ├── Dissonant_1 │ │ ├── Dissonant_2 │ │ ├── Dyna_EP_Bright │ │ ├── Dyna_EP_Med │ │ ├── Ethnic_33 │ │ ├── Full_1 │ │ ├── Full_2 │ │ ├── Guitar_Fuzz │ │ ├── Harsh │ │ ├── Mkl_Hard │ │ ├── Organ_2 │ │ ├── Organ_3 │ │ ├── Phoneme_ah │ │ ├── Phoneme_bah │ │ ├── Phoneme_ee │ │ ├── Phoneme_o │ │ ├── Phoneme_ooh │ │ ├── Phoneme_pop_ahhhs │ │ ├── Piano │ │ ├── Putney_Wavering │ │ ├── Throaty │ │ ├── Trombone │ │ ├── Twelve String Guitar 1 │ │ ├── Twelve_OpTines │ │ ├── Wurlitzer │ │ └── Wurlitzer_2 ├── experiments │ ├── index.njk │ └── webgpuaudio │ │ ├── README.md │ │ ├── assets.js │ │ ├── basic-processor.js │ │ ├── coi-serviceworker.js │ │ ├── constants.js │ │ ├── gpu-processor.js │ │ ├── index.njk │ │ ├── ir-helper.js │ │ ├── lib │ │ └── free-queue.js │ │ ├── main.js │ │ ├── style.css │ │ ├── test │ │ ├── index.html │ │ ├── test_page_handler.js │ │ └── test_processor.js │ │ └── worker.js ├── index.njk ├── lib │ └── free-queue │ │ ├── README.md │ │ ├── coi-serviceworker.js │ │ ├── free-queue-sab.js │ │ ├── free-queue.js │ │ └── test │ │ ├── free-queue-sab.test.html │ │ ├── free-queue-sab.test.js │ │ ├── free-queue.test.html │ │ └── free-queue.test.js ├── library │ ├── FIFO.js │ ├── VUMeter.js │ └── Waveform.js ├── rainfly │ ├── .eslintrc.json │ ├── .gitignore │ ├── .npmrc │ ├── README.md │ ├── jsconfig.json │ ├── package.json │ ├── postcss.config.js │ ├── src │ │ ├── app.css │ │ ├── app.d.ts │ │ ├── app.html │ │ ├── lib │ │ │ ├── actions │ │ │ │ ├── click-outside.js │ │ │ │ └── portal.js │ │ │ ├── assets │ │ │ │ ├── logo.svg │ │ │ │ ├── player-pause.svg │ │ │ │ ├── player-play.svg │ │ │ │ ├── player-run-play.svg │ │ │ │ ├── player-stop.svg │ │ │ │ └── vim.svg │ │ │ ├── components │ │ │ │ ├── ActionButton.svelte │ │ │ │ ├── Editor.svelte │ │ │ │ ├── Modal.svelte │ │ │ │ ├── Toast.svelte │ │ │ │ ├── Tooltip.svelte │ │ │ │ ├── Visualizer.svelte │ │ │ │ └── nav │ │ │ │ │ ├── Nav.svelte │ │ │ │ │ ├── NavDropdownItem.svelte │ │ │ │ │ ├── NavItem.svelte │ │ │ │ │ └── items │ │ │ │ │ ├── NavExamples.svelte │ │ │ │ │ ├── NavFile.svelte │ │ │ │ │ └── NavHelp.svelte │ │ │ ├── stores │ │ │ │ ├── status.js │ │ │ │ └── vim-status.js │ │ │ └── utils │ │ │ │ ├── audio-buffer-to-wav.js │ │ │ │ ├── audio-host.js │ │ │ │ ├── click-outside.js │ │ │ │ ├── file-utils.js │ │ │ │ └── monaco.js │ │ └── routes │ │ │ ├── +layout.js │ │ │ ├── +layout.svelte │ │ │ └── +page.svelte │ ├── static │ │ ├── examples │ │ │ ├── bypass │ │ │ │ ├── main.js │ │ │ │ └── processor.js │ │ │ ├── examples.json │ │ │ └── sine │ │ │ │ ├── main.js │ │ │ │ └── processor.js │ │ ├── favicon.svg │ │ ├── processor │ │ │ └── recorder-processor.js │ │ └── splash.svg │ ├── svelte.config.js │ ├── tailwind.config.js │ └── vite.config.js ├── robots.txt ├── sitemap.xml ├── sounds │ ├── drum-samples │ │ ├── 4OP-FM │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ │ ├── CR78 │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ │ ├── KPR77 │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ │ ├── Kit3 │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ │ ├── Kit8 │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ │ ├── LINN │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ │ ├── R8 │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ │ ├── Stark │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ │ ├── Techno │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ │ ├── TheCheebacabra1 │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ │ ├── TheCheebacabra2 │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ │ ├── acoustic-kit │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ │ ├── breakbeat13 │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ │ ├── breakbeat8 │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ │ └── breakbeat9 │ │ │ ├── hihat.wav │ │ │ ├── kick.wav │ │ │ ├── snare.wav │ │ │ ├── tom1.wav │ │ │ ├── tom2.wav │ │ │ └── tom3.wav │ ├── fx │ │ ├── ball-ball-hard2.wav │ │ ├── ball-ball-light2.wav │ │ ├── ball-ball-medium3.wav │ │ ├── ball-edge-hard1.wav │ │ ├── ball-edge-medium2.wav │ │ ├── ball-pocket-balls.wav │ │ ├── cauldron.wav │ │ ├── filter-noise-2.wav │ │ ├── human-voice.mp3 │ │ ├── obama-oilspill.mp3 │ │ ├── penny-spinning.wav │ │ ├── stick-cue-light2.wav │ │ ├── stick-cue-medium2.wav │ │ ├── stick-cue-medium5.wav │ │ ├── ticking.wav │ │ ├── waves.wav │ │ └── white-noise.wav │ ├── impulse-responses │ │ ├── ambisonic-1o-ir.wav │ │ ├── backslap1.wav │ │ ├── binaural-s3_r4_bd.wav │ │ ├── cardiod-35-10-spread.wav │ │ ├── cardiod-rear-35-10.wav │ │ ├── cardiod-true-stereo-15-8.wav │ │ ├── comb-saw1.wav │ │ ├── comb-saw2.wav │ │ ├── cosmic-ping-long.wav │ │ ├── diffusor3.wav │ │ ├── echo-chamber.wav │ │ ├── feedback-spring.wav │ │ ├── filter-hipass5000.wav │ │ ├── filter-lopass160.wav │ │ ├── filter-rhythm3.wav │ │ ├── filter-telephone.wav │ │ ├── kitchen-true-stereo.wav │ │ ├── matrix-reverb2.wav │ │ ├── matrix-reverb3.wav │ │ ├── matrix-reverb6.wav │ │ ├── matrix6-backwards.wav │ │ ├── noise-spreader1.wav │ │ ├── omni-35-10.wav │ │ ├── peculiar-backwards.wav │ │ ├── sifter.wav │ │ ├── spatialized1.wav │ │ ├── spatialized2.wav │ │ ├── spatialized3.wav │ │ ├── spatialized4.wav │ │ ├── spatialized5.wav │ │ ├── spatialized6.wav │ │ ├── spatialized7.wav │ │ ├── spatialized8.wav │ │ ├── spatialized9.wav │ │ ├── spreader50-65ms.wav │ │ ├── super-ceiling-35-10.wav │ │ ├── tim-stretch2.wav │ │ ├── tim-warehouse-stretch1.wav │ │ └── wildecho.wav │ └── loops │ │ ├── blueyellow.wav │ │ ├── break12.wav │ │ ├── break28.wav │ │ ├── break29.wav │ │ ├── breakbeat.wav │ │ ├── coolloop7.wav │ │ ├── ominous.wav │ │ └── organ-echo-chords.wav ├── styles │ └── styles.css └── tests │ ├── index.njk │ ├── pannernode │ ├── app.js │ └── index.njk │ ├── playwright │ ├── README.md │ ├── pages │ │ ├── chuck-realtime-sine.html │ │ ├── index.html │ │ ├── live-suite │ │ │ ├── scripts │ │ │ │ ├── console-override.js │ │ │ │ ├── main.js │ │ │ │ └── test-file-converter.js │ │ │ └── style.css │ │ ├── perf-audio-buffer-source-node.html │ │ ├── perf-audio-worklet-node.html │ │ ├── perf-biquad-filter-node.html │ │ ├── perf-dynamics-compressor-node-knee.html │ │ ├── perf-dynamics-compressor-node-post-knee.html │ │ ├── perf-dynamics-compressor-node-pre-knee.html │ │ ├── perf-gain-node.html │ │ ├── perf-panner-node.html │ │ ├── perf-timeline-insert-event.html │ │ ├── realtime-sine.html │ │ ├── reference │ │ │ └── 440@48k-sine-octx.json │ │ ├── template.html │ │ ├── tests.json │ │ └── util │ │ │ ├── audit.js │ │ │ ├── bypass-processor.js │ │ │ └── recorder │ │ │ ├── recorder-main.js │ │ │ └── recorder-processor.js │ ├── runner.spec.ts │ └── version.spec.ts │ ├── resampler-smoke │ ├── app.js │ └── index.njk │ ├── resampler │ ├── app.js │ └── index.njk │ └── setsinkid │ ├── app.js │ └── index.njk └── tailwind.config.js /.eleventyignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | ./src/archive/ 3 | **/README.md 4 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "google" 9 | ], 10 | "ignorePatterns": [ 11 | "_site/**/*.wasm.js", 12 | "_site/**/*.wasmmodule.js", 13 | "_site/archive/", 14 | "_site/**/build/*", 15 | "_site/**/coi-serviceworker.js" 16 | ], 17 | "parserOptions": { 18 | "ecmaVersion": 12, 19 | "sourceType": "module" 20 | }, 21 | "rules": { 22 | "require-jsdoc": 0 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI and Lint 2 | 3 | on: 4 | pull_request: 5 | branches: [ main ] 6 | 7 | jobs: 8 | lint: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout code 12 | uses: actions/checkout@v4 13 | with: 14 | fetch-depth: 0 15 | 16 | - name: Set up Node.js 17 | uses: actions/setup-node@v4 18 | with: 19 | node-version: 18 20 | 21 | - name: Install dependencies 22 | run: npm ci 23 | 24 | - name: Lint changed files 25 | if: github.event_name == 'pull_request' 26 | run: | 27 | git fetch origin ${{ github.base_ref }} 28 | FILES=$(git diff --name-only origin/${{ github.base_ref }} ${{ github.sha }} | grep -E '\.(js|jsx|ts|tsx|html|css)$' || true) 29 | if [ -n "$FILES" ]; then 30 | echo "Linting changed files:" 31 | echo "$FILES" 32 | echo "$FILES" | xargs npx prettier --check 33 | echo "$FILES" | grep -E '\.(js|jsx|ts|tsx)$' | xargs npx eslint || true 34 | else 35 | echo "No relevant files changed." 36 | fi 37 | env: 38 | CI: true -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build and deploy to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | permissions: 10 | contents: write 11 | 12 | jobs: 13 | deploy: 14 | name: Build and deploy to GitHub Pages 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Check out this repo 18 | uses: actions/checkout@v3 19 | - name: Install Node.js 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: 18 23 | - name: npm install and build 24 | run: | 25 | npm install 26 | npm run build 27 | - name: deploy _site to gh-pages 28 | uses: s0/git-publish-subdir-action@develop 29 | env: 30 | REPO: self 31 | BRANCH: gh-pages 32 | FOLDER: _site 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | -------------------------------------------------------------------------------- /.github/workflows/playwright.yml: -------------------------------------------------------------------------------- 1 | name: Playwright Tests 2 | on: 3 | push: 4 | branches: [ main, master ] 5 | pull_request: 6 | branches: [ main, master ] 7 | jobs: 8 | test: 9 | timeout-minutes: 60 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - uses: actions/setup-node@v4 14 | with: 15 | node-version: lts/* 16 | - name: Install dependencies 17 | run: npm ci 18 | - name: Install Playwright Browsers 19 | run: npx playwright install --with-deps chromium 20 | - name: Run Playwright tests 21 | # Only test on Chromium 22 | # Each version of playwright is tied to the latest version of Chromium (at the time). The version is listed here: 23 | # https://github.com/microsoft/playwright?tab=readme-ov-file#documentation--api-reference 24 | run: npx playwright test --project=chromium 25 | - uses: actions/upload-artifact@v4 26 | if: always() 27 | with: 28 | name: playwright-report 29 | path: playwright-report/ 30 | retention-days: 30 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | _site/ 4 | 5 | ## Playwright-specific ignores 6 | /test-results/ 7 | /playwright-report/ 8 | /blob-report/ 9 | /playwright/.cache/ 10 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "tabWidth": 2, 5 | "useTabs": false, 6 | "trailingComma": "es5", 7 | "bracketSpacing": true, 8 | "arrowParens": "always", 9 | "printWidth": 80 10 | } -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # CONTRIBUTORS 2 | 3 | @Dp-Goog https://github.com/Dp-Goog 4 | @duojet2ez https://github.com/duojet2ez 5 | @Kizjkre https://github.com/Kizjkre 6 | @sisi-sh https://github.com/sisi-sh 7 | Abhay Gupta https://github.com/professorabhay 8 | Divyam Ahuja https://github.com/DivyamAhuja 9 | Tarun Singh https://github.com/tarunsinghofficial 10 | Tenghui Zhang https://github.com/TenghuiZhang 11 | Terry Feng https://github.com/terryzfeng 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Web Audio Samples by Chrome Web Audio Team 2 | 3 | This branch contains the source codes of the Web Audio Samples site. See the 4 | actual site built from the source, see `gh-pages` branch. 5 | 6 | ## Development 7 | 8 | ### Branch structure 9 | - `main`: site source 10 | - `gh-pages`: the actual site built from `main` 11 | - `archive`: old projects/examples (V2 and earlier) 12 | 13 | ### How to make changes and depoly 14 | 15 | 1. Clone the repository. 16 | 2. `npm install` 17 | 3. To fire up the local dev server, `npm run start`. 18 | 4. Make sure to run `npm run format` to apply linting/formatting. 19 | 5. To deploy, `npm run deploy` 20 | 21 | ## Support 22 | 23 | If you have found an error in this library, please file an issue at: 24 | https://github.com/GoogleChromeLabs/web-audio-samples/issues. 25 | 26 | ## Contribution 27 | 28 | Patches are encouraged, and may be submitted by forking this project and 29 | submitting a pull request through GitHub. See CONTRIBUTING.md for more detail. 30 | 31 | ## License 32 | 33 | Copyright 2018 Google, Inc. 34 | 35 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 36 | this file except in compliance with the License. You may obtain a copy of the 37 | License at 38 | 39 | http://www.apache.org/licenses/LICENSE-2.0 40 | 41 | Unless required by applicable law or agreed to in writing, software distributed 42 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 43 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 44 | specific language governing permissions and limitations under the License. 45 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | This document is a placeholder for the `docs\` directory. 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-audio-samples", 3 | "version": "3.2.1", 4 | "description": "A collection of projects, examples and resources for Web Audio API. Curated by the Chrome Web Audio team.", 5 | "main": "index.js", 6 | "scripts": { 7 | "clean": "rimraf _site", 8 | "build": "npm run clean && run-p build:*", 9 | "build:eleventy": "ELEVENTY_ENV=production eleventy", 10 | "build:postcss": "ELEVENTY_ENV=production postcss src/styles/*.css --dir _site", 11 | "build:rainfly": "cd src/rainfly && npm run build", 12 | "start": "run-p start:*", 13 | "start:eleventy": "eleventy --serve", 14 | "start:postcss": "postcss src/styles/*.css --dir _site --watch", 15 | "format": "npx eslint --fix _site/audio-worklet/**/*.js && npx prettier --write --loglevel silent _site/audio-worklet/**/*.html", 16 | "test": "npx playwright test", 17 | "test-server": "npx http-server", 18 | "test-live": "npx http-server ./src/tests/playwright/pages/" 19 | }, 20 | "license": "MIT", 21 | "dependencies": { 22 | "@11ty/eleventy": "^2.0.1", 23 | "@11ty/eleventy-navigation": "^0.3.5", 24 | "autoprefixer": "^10.4.21", 25 | "cssnano": "^7.0.6", 26 | "eslint": "9.23.0", 27 | "eslint-config-google": "^0.14.0", 28 | "html-minifier": "^4.0.0", 29 | "js-yaml": "^4.1.0", 30 | "npm-run-all": "^4.1.5", 31 | "postcss": "^8.5.3", 32 | "postcss-cli": "^11.0.1", 33 | "prettier": "^3.5.3", 34 | "rimraf": "^6.0.1", 35 | "tailwindcss": "^3.4.14" 36 | }, 37 | "devDependencies": { 38 | "@playwright/test": "latest", 39 | "@types/node": "^20.12.13" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /playwright.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, devices } from '@playwright/test'; 2 | 3 | /** 4 | * See https://playwright.dev/docs/test-configuration. 5 | */ 6 | export default defineConfig({ 7 | testDir: './src/tests/playwright', 8 | // Run tests in files in parallel 9 | fullyParallel: true, 10 | // Fail the build on CI if you accidentally left test.only in the source code. 11 | forbidOnly: !!process.env.CI, 12 | // Retry on CI only 13 | retries: process.env.CI ? 2 : 0, 14 | // Opt out of parallel tests on CI. 15 | workers: process.env.CI ? 1 : undefined, 16 | // Reporter to use. See https://playwright.dev/docs/test-reporters 17 | reporter: 'html', 18 | // Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. 19 | use: { 20 | // Base URL to use in actions like `await page.goto('/')`. 21 | baseURL: 'http://127.0.0.1:8080/src/tests/playwright/', 22 | // Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer 23 | trace: 'on-first-retry', 24 | }, 25 | 26 | // Configure projects for major browsers 27 | projects: [ 28 | { 29 | name: 'chromium', 30 | use: { 31 | ...devices['Desktop Chrome'], 32 | launchOptions: { 33 | ignoreDefaultArgs: ['--mute-audio'], 34 | args: ['--autoplay-policy=no-user-gesture-required'] 35 | }, 36 | } 37 | } 38 | ], 39 | 40 | // Run your local dev server before starting the tests 41 | webServer: { 42 | command: 'npm run test-server', 43 | url: 'http://127.0.0.1:8080', 44 | reuseExistingServer: !process.env.CI, 45 | }, 46 | }); 47 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | const cssNanoProductionOptions = { 2 | preset: [ 3 | 'default', 4 | {discardComments: {removeAll: true}} 5 | ] 6 | }; 7 | 8 | module.exports = ({env}) => ({ 9 | plugins: { 10 | tailwindcss: {}, 11 | autoprefixer: {}, 12 | cssnano: env === 'production' ? cssNanoProductionOptions : false 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /src/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. 4 | 5 | ## Before you begin 6 | 7 | ### Sign our Contributor License Agreement 8 | 9 | Contributions to this project must be accompanied by a 10 | [Contributor License Agreement](https://cla.developers.google.com/about) (CLA). 11 | You (or your employer) retain the copyright to your contribution; this simply 12 | gives us permission to use and redistribute your contributions as part of the 13 | project. 14 | 15 | If you or your current employer have already signed the Google CLA (even if it 16 | was for a different project), you probably don't need to do it again. 17 | 18 | Visit to see your current agreements or to 19 | sign a new one. 20 | 21 | ### Review our Community Guidelines 22 | 23 | This project follows 24 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/). 25 | 26 | ## Contribution process 27 | 28 | ### Code Reviews 29 | 30 | All submissions, including submissions by project members, require review. We 31 | use GitHub pull requests for this purpose. Consult 32 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 33 | information on using pull requests. 34 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # Web Audio Samples by Chrome Web Audio Team 2 | 3 | This branch contains the actual site built from the source code. For the 4 | source for editing and publishing, see `main` branch. -------------------------------------------------------------------------------- /src/_data/build_info.json: -------------------------------------------------------------------------------- 1 | {"version":"3.2.1","revision":"4d904e3","lastUpdated":"2025-03-24","copyrightYear":2025} -------------------------------------------------------------------------------- /src/_data/experiments_data.yaml: -------------------------------------------------------------------------------- 1 | - title: Experiments 2 | entries: 3 | - title: WebGPUAudio 4 | description: WebGPUAudio 5 | href: webgpuaudio/ -------------------------------------------------------------------------------- /src/_data/footer_data.yaml: -------------------------------------------------------------------------------- 1 | links: 2 | - title: Home 3 | href: https://googlechromelabs.github.io/web-audio-samples/ 4 | - title: Sources 5 | href: https://github.com/GoogleChromeLabs/web-audio-samples/ 6 | - title: Report issues 7 | href: https://github.com/GoogleChromeLabs/web-audio-samples/issues/new 8 | - title: Report Chrome issues 9 | href: https://bugs.chromium.org/p/chromium/issues/entry?components=Blink%3EWebAudio 10 | -------------------------------------------------------------------------------- /src/_data/global_data.yaml: -------------------------------------------------------------------------------- 1 | githubUrl: https://github.com/GoogleChromeLabs/web-audio-samples/tree/main/src -------------------------------------------------------------------------------- /src/_data/tests_data.yaml: -------------------------------------------------------------------------------- 1 | - title: Tests 2 | entries: 3 | - title: AudioContext.setSinkId() 4 | description: A manual test for setSinkId() API 5 | href: setsinkid/ 6 | - title: Performance of PannerNode and AudioListener 7 | description: Manual test for performance of PannerNode and AudioListener 8 | href: pannernode/ 9 | - title: Web Audio Live Test Suite 10 | description: "An interactive webpage for running performance and benchmark tests locally in your browser and 11 | monitoring runtime" 12 | href: playwright/pages/ 13 | -------------------------------------------------------------------------------- /src/_includes/example-source-code.njk: -------------------------------------------------------------------------------- 1 |
2 | 3 | source code 4 | 5 |
-------------------------------------------------------------------------------- /src/_includes/footer.njk: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /src/_includes/header.njk: -------------------------------------------------------------------------------- 1 | {% set breadcrumbData = 2 | collections.all | eleventyNavigationBreadcrumb(eleventyNavigation.key) %} 3 | 4 |
5 | {% for destination in breadcrumbData %} 6 | 11 | 12 | ▸ 13 | 14 | {% endfor %} 15 |
16 | {{ eleventyNavigation.title }} 17 |
18 |
19 | -------------------------------------------------------------------------------- /src/audio-worklet/basic/bit-crusher/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: bit-crusher-with-audioparam 4 | title: BitCrusher with AudioParam 5 | parent: audio-worklet 6 | to_root_dir: ../../../ 7 | --- 8 | 9 | {% extends "../../../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |

{{ eleventyNavigation.title }}

14 |

A BitCrusher example from the Web Audio API specification, but modified to 15 | demonstrate AudioParam automations. The sound source is a sawtooth oscillator 16 | at 5000Hz. The demo runs for 8 seconds.

17 |

See 18 | 19 | Chrome Developers Article: Enter Audio Worklet for more information.

20 | 21 |
22 | 23 | {% include "../../../_includes/example-source-code.njk" %} 24 |
25 | 26 | 27 | 28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /src/audio-worklet/basic/handling-errors/error-processor.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /** 6 | * A processor with an error in its constructor. 7 | * 8 | * @class ConstructorErrorProcessor 9 | * @extends AudioWorkletProcessor 10 | */ 11 | class ConstructorErrorProcessor extends AudioWorkletProcessor { 12 | constructor() { 13 | throw new Error( 14 | 'ConstructorErrorProcessor: an error thrown from constructor.'); 15 | } 16 | 17 | process() { 18 | return true; 19 | } 20 | } 21 | 22 | 23 | /** 24 | * A processor with an error in its process callback. 25 | * 26 | * @class ProcessErrorProcessor 27 | * @extends AudioWorkletProcessor 28 | */ 29 | class ProcessErrorProcessor extends AudioWorkletProcessor { 30 | constructor() { 31 | super(); 32 | } 33 | 34 | process() { 35 | throw new Error( 36 | 'ProcessErrorProcessor: an error throw from process method.'); 37 | } 38 | } 39 | 40 | 41 | registerProcessor('constructor-error', ConstructorErrorProcessor); 42 | registerProcessor('process-error', ProcessErrorProcessor); 43 | -------------------------------------------------------------------------------- /src/audio-worklet/basic/handling-errors/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: handling-error 4 | title: Handling Errors 5 | parent: audio-worklet 6 | to_root_dir: ../../../ 7 | --- 8 | 9 | {% extends "../../../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |

{{ eleventyNavigation.title }}

14 |

A simple demonstration on how to catch an error from AudioWorkletProcessor 15 | with onprocessorerror event handler in AudioWorkletNode. Open up the console 16 | to see the events being fired.

17 |

See 18 | 19 | Chrome Developers Article: Enter Audio Worklet for more information.

20 | 21 |
22 | 23 | {% include "../../../_includes/example-source-code.njk" %} 24 |
25 | 26 | 27 | 28 | {% endblock %} -------------------------------------------------------------------------------- /src/audio-worklet/basic/hello-audio-worklet/bypass-processor.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /** 6 | * A simple bypass node demo. 7 | * 8 | * @class BypassProcessor 9 | * @extends AudioWorkletProcessor 10 | */ 11 | class BypassProcessor extends AudioWorkletProcessor { 12 | // When constructor() undefined, the default constructor will be implicitly 13 | // used. 14 | 15 | process(inputs, outputs) { 16 | // By default, the node has single input and output. 17 | const input = inputs[0]; 18 | const output = outputs[0]; 19 | 20 | for (let channel = 0; channel < output.length; ++channel) { 21 | output[channel].set(input[channel]); 22 | } 23 | 24 | return true; 25 | } 26 | } 27 | 28 | registerProcessor('bypass-processor', BypassProcessor); 29 | -------------------------------------------------------------------------------- /src/audio-worklet/basic/hello-audio-worklet/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: hello-audio-worklet 4 | title: Hello Audio Worklet! 5 | parent: audio-worklet 6 | to_root_dir: ../../../ 7 | --- 8 | 9 | {% extends "../../../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |

{{ eleventyNavigation.title }}

14 |

A simple AudioWorkletNode that bypasses the incoming audio stream to its 15 | output. The sound source a sine oscillator at 440Hz.

16 |

See 17 | 18 | Chrome Developers Article: Enter Audio Worklet for more information.

19 | 20 |
21 | 22 | {% include "../../../_includes/example-source-code.njk" %} 23 |
24 | 25 | 26 | 27 | {% endblock %} -------------------------------------------------------------------------------- /src/audio-worklet/basic/hello-audio-worklet/main.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const audioContext = new AudioContext(); 6 | let isModuleLoaded = false; 7 | let isPlaying = false; 8 | let isGraphReady = false; 9 | let oscillatorNode = null; 10 | 11 | const loadGraph = (context) => { 12 | oscillatorNode = new OscillatorNode(context); 13 | const bypasser = new AudioWorkletNode(context, 'bypass-processor'); 14 | oscillatorNode.connect(bypasser).connect(context.destination); 15 | oscillatorNode.start(); 16 | }; 17 | 18 | const startAudio = async (context) => { 19 | if (!isModuleLoaded) { 20 | await context.audioWorklet.addModule('bypass-processor.js'); 21 | isModuleLoaded = true; 22 | } 23 | if (!isGraphReady) { 24 | loadGraph(audioContext); 25 | isGraphReady = true; 26 | } 27 | }; 28 | 29 | // A simplem onLoad handler. It also handles user gesture to unlock the audio 30 | // playback. 31 | window.addEventListener('load', async () => { 32 | const buttonEl = document.getElementById('button-start'); 33 | buttonEl.disabled = false; 34 | 35 | buttonEl.addEventListener('click', async () => { 36 | if (!isPlaying) { 37 | await startAudio(audioContext); 38 | isPlaying = true; 39 | buttonEl.textContent = 'Playing...'; 40 | buttonEl.classList.remove('start-button'); 41 | audioContext.resume(); 42 | } else { 43 | audioContext.suspend(); 44 | isPlaying = false; 45 | buttonEl.textContent = 'START'; 46 | buttonEl.classList.add('start-button'); 47 | } 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/audio-worklet/basic/message-port/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: message-port 4 | title: MessagePort 5 | parent: audio-worklet 6 | to_root_dir: ../../../ 7 | --- 8 | 9 | {% extends "../../../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |

{{ eleventyNavigation.title }}

14 |

Demonstrates basic bi-directional communication between AudioWorkletNode and 15 | AudioWorkletProcessor. Open up the console to see the events being fired.

16 |

See 17 | 18 | Chrome Developers Article: Enter Audio Worklet for more information.

19 | 20 |
21 | 22 | {% include "../../../_includes/example-source-code.njk" %} 23 |
24 | 25 | 26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /src/audio-worklet/basic/message-port/messenger-processor.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /* global currentTime */ 6 | 7 | /** 8 | * A simple MessagePort tester. 9 | * 10 | * @class MessengerProcessor 11 | * @extends AudioWorkletProcessor 12 | */ 13 | class MessengerProcessor extends AudioWorkletProcessor { 14 | constructor() { 15 | super(); 16 | this._lastUpdate = currentTime; 17 | this.port.onmessage = this.handleMessage_.bind(this); 18 | } 19 | 20 | handleMessage_(event) { 21 | console.log('[Processor:Received] ' + event.data.message + 22 | ' (' + event.data.contextTimestamp + ')'); 23 | } 24 | 25 | process() { 26 | // Post a message to the node for every 1 second. 27 | if (currentTime - this._lastUpdate > 1.0) { 28 | this.port.postMessage({ 29 | message: '1 second passed.', 30 | contextTimestamp: currentTime, 31 | }); 32 | this._lastUpdate = currentTime; 33 | } 34 | 35 | return true; 36 | } 37 | } 38 | 39 | registerProcessor('messenger-processor', MessengerProcessor); 40 | -------------------------------------------------------------------------------- /src/audio-worklet/basic/noise-generator/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: noise-generator-with-modulation 4 | title: Noise generator with modulation 5 | parent: audio-worklet 6 | to_root_dir: ../../../ 7 | --- 8 | 9 | {% extends "../../../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |

{{ eleventyNavigation.title }}

14 |

A simple noise generator with a user-defined AudioParam modulated by an 15 | OscillatorNode. The modulation on a gain parameter creates a tremolo effect. 16 |

17 |

See 18 | 19 | Chrome Developers Article: Enter Audio Worklet for more information.

20 | 21 |
22 | 23 | {% include "../../../_includes/example-source-code.njk" %} 24 |
25 | 26 | 27 | 28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /src/audio-worklet/basic/one-pole-filter/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: one-pole-filter 4 | title: One Pole Filter 5 | parent: audio-worklet 6 | to_root_dir: ../../../ 7 | --- 8 | 9 | {% extends "../../../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |

{{ eleventyNavigation.title }}

14 |

A one pole filter implementation with AudioWorkletNode. A noise generator 15 | goes into an one-pole filter and a series of AudioParam automations is in 16 | action to move the filter frequency.

17 |

See 18 | 19 | Chrome Developers Article: Enter Audio Worklet for more information.

20 | 21 |
22 | 23 | {% include "../../../_includes/example-source-code.njk" %} 24 |
25 | 26 | 27 | 28 | {% endblock %} -------------------------------------------------------------------------------- /src/audio-worklet/basic/volume-meter/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: volume-meter 4 | title: Volume Meter 5 | parent: audio-worklet 6 | to_root_dir: ../../../ 7 | --- 8 | 9 | {% extends "../../../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |

{{ eleventyNavigation.title }}

14 |

Measures microphone volume with AudioWorkletProcessor.

15 |

See 16 | 17 | Chrome Developers Article: Enter Audio Worklet for more information.

18 | 19 |
20 |
21 | 23 |
24 | 25 | {% include "../../../_includes/example-source-code.njk" %} 26 |
27 | 28 | 29 | 30 | {% endblock %} -------------------------------------------------------------------------------- /src/audio-worklet/basic/volume-meter/volume-meter-processor.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /* global currentTime */ 6 | 7 | const SMOOTHING_FACTOR = 0.8; 8 | const FRAME_PER_SECOND = 60; 9 | const FRAME_INTERVAL = 1 / FRAME_PER_SECOND; 10 | 11 | /** 12 | * Measure microphone volume. 13 | * 14 | * @class VolumeMeter 15 | * @extends AudioWorkletProcessor 16 | */ 17 | class VolumeMeter extends AudioWorkletProcessor { 18 | 19 | constructor() { 20 | super(); 21 | this._lastUpdate = currentTime; 22 | this._volume = 0; 23 | } 24 | 25 | calculateRMS(inputChannelData) { 26 | // Calculate the squared-sum. 27 | let sum = 0; 28 | for (let i = 0; i < inputChannelData.length; i++) { 29 | sum += inputChannelData[i] * inputChannelData[i]; 30 | } 31 | 32 | // Calculate the RMS level and update the volume. 33 | let rms = Math.sqrt(sum / inputChannelData.length); 34 | this._volume = Math.max(rms, this._volume * SMOOTHING_FACTOR); 35 | } 36 | 37 | process(inputs, outputs) { 38 | // This example only handles mono channel. 39 | const inputChannelData = inputs[0][0]; 40 | 41 | // Post a message to the node every 16ms. 42 | if (currentTime - this._lastUpdate > FRAME_INTERVAL) { 43 | this.calculateRMS(inputChannelData); 44 | this.port.postMessage(this._volume); 45 | this._lastUpdate = currentTime; 46 | } 47 | 48 | return true; 49 | } 50 | } 51 | 52 | registerProcessor("volume-meter", VolumeMeter); -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/lib/em-es6-module.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | /* global Module */ 18 | 19 | // EXPORT_ES6 option does not work as described at 20 | // https://github.com/kripken/emscripten/issues/6284, so we have to 21 | // manually add this by '--post-js' setting when the Emscripten compilation. 22 | export default Module; 23 | -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/shared-buffer/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: audioworklet-sharedarraybuffer-and-worker 4 | title: AudioWorklet, SharedArrayBuffer, and Worker 5 | parent: audio-worklet 6 | to_root_dir: ../../../ 7 | --- 8 | 9 | {% extends to_root_dir + "_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 | 14 | 15 |

{{ eleventyNavigation.title }}

16 |

This example demonstrates how to take advantage of Worker thread and 17 | SharedArrayBuffer in conjunction with AudioWorklet. This pattern is useful 18 | when bringing legacy audio application written in C/C++ into the web 19 | platform.

20 |

See 21 | Chrome Developers Article: Audio Worklet Design Pattern 23 | for more details.

24 | 25 |
26 | 27 | {% include to_root_dir + "_includes/example-source-code.njk" %} 28 |
29 | 30 | 31 | 32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/shared-buffer/main.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const audioContext = new AudioContext(); 6 | 7 | const startAudio = async (context) => { 8 | // Import the pre-defined AudioWorkletNode subclass dynamically. This is 9 | // invoked only when Audio Worklet is detected. 10 | const {default: SharedBufferWorkletNode} = 11 | await import('./shared-buffer-worklet-node.js'); 12 | 13 | await context.audioWorklet.addModule('shared-buffer-worklet-processor.js'); 14 | const oscillator = new OscillatorNode(context); 15 | const sbwNode = new SharedBufferWorkletNode(context); 16 | 17 | sbwNode.onInitialized = () => { 18 | oscillator.connect(sbwNode).connect(context.destination); 19 | oscillator.start(); 20 | }; 21 | 22 | sbwNode.onError = (errorData) => { 23 | console.log('[ERROR] ' + errorData.detail); 24 | }; 25 | }; 26 | 27 | // A simple onLoad handler. It also handles user gesture to unlock the audio 28 | // playback. 29 | window.addEventListener('load', async () => { 30 | const buttonEl = document.getElementById('button-start'); 31 | buttonEl.disabled = false; 32 | buttonEl.addEventListener('click', async () => { 33 | await startAudio(audioContext); 34 | audioContext.resume(); 35 | buttonEl.disabled = true; 36 | buttonEl.textContent = 'Playing...'; 37 | }, false); 38 | }); 39 | -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/wasm-ring-buffer/Makefile: -------------------------------------------------------------------------------- 1 | DEPS = VariableBufferKernel.cc 2 | 3 | build: $(DEPS) 4 | @emcc --bind -O1 \ 5 | -s WASM=1 \ 6 | -s BINARYEN_ASYNC_COMPILATION=0 \ 7 | -s SINGLE_FILE=1 \ 8 | VariableBufferKernel.cc \ 9 | -o variable-buffer-kernel.wasmmodule.js \ 10 | --post-js ../lib/em-es6-module.js 11 | 12 | clean: 13 | @rm -f variable-buffer-kernel.wasmmodule.js 14 | -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/wasm-ring-buffer/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: ring-buffer-in-audioworkletprocessor 4 | title: Ring Buffer in AudioWorkletProcessor 5 | parent: audio-worklet 6 | to_root_dir: ../../../ 7 | --- 8 | 9 | {% extends to_root_dir + "_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |

{{ eleventyNavigation.title }}

14 |

This example demonstrates how to handle different buffer sizes between the 15 | C++ audio processing kernel (1024 sample frames) and AudioWorkletProcessor 16 | (128 sample frames).

17 |

See 18 | Chrome Developers Article: Audio Worklet Design Pattern 20 | for more details.

21 | 22 |
23 | 24 | {% include to_root_dir + "_includes/example-source-code.njk" %} 25 |
26 | 27 | 28 | 29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/wasm-ring-buffer/main.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const audioContext = new AudioContext(); 6 | 7 | const startAudio = async (context) => { 8 | await context.audioWorklet.addModule('ring-buffer-worklet-processor.js'); 9 | const oscillator = new OscillatorNode(context); 10 | const ringBufferWorkletNode = 11 | new AudioWorkletNode(context, 'ring-buffer-worklet-processor', { 12 | processorOptions: { 13 | kernelBufferSize: 1024, 14 | channelCount: 1, 15 | }, 16 | }); 17 | 18 | oscillator.connect(ringBufferWorkletNode).connect(context.destination); 19 | oscillator.start(); 20 | }; 21 | 22 | // A simplem onLoad handler. It also handles user gesture to unlock the audio 23 | // playback. 24 | window.addEventListener('load', async () => { 25 | const buttonEl = document.getElementById('button-start'); 26 | buttonEl.disabled = false; 27 | buttonEl.addEventListener('click', async () => { 28 | await startAudio(audioContext); 29 | audioContext.resume(); 30 | buttonEl.disabled = true; 31 | buttonEl.textContent = 'Playing...'; 32 | }, false); 33 | }); 34 | -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/wasm-supersaw/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google Inc. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #!/bin/bash 16 | 17 | DEPS = $(wildcard ./synth_src/*.cpp) 18 | 19 | build: $(DEPS) 20 | @emcc \ 21 | --bind \ 22 | --post-js ../lib/em-es6-module.js \ 23 | -s ENVIRONMENT=shell \ 24 | -s SINGLE_FILE=1 \ 25 | -s WASM=1 \ 26 | -s WASM_ASYNC_COMPILATION=0 \ 27 | -s EXPORTED_FUNCTIONS="['_malloc']" \ 28 | -o ./synth.wasm.js \ 29 | ./synth_src/synth_bind.cc $(DEPS) 30 | 31 | @echo "Build complete: ./synth.wasm.js" 32 | -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/wasm-supersaw/README.md: -------------------------------------------------------------------------------- 1 | # How to use wasm-supersaw example 2 | 3 | Unlike other AudioWorklet examples in this repository, this examples needs 4 | an additional step to build and compile. Follow the steps below: 5 | 6 | 1. Install Emscripten in your development setup. Follow the instruction: 7 | https://emscripten.org/docs/getting_started/downloads.html 8 | 9 | 2. Run `emcc -v` to confirm the Emscripten installation and its version. This 10 | example needs 3.1.48 or later to work correctly. (See 11 | [this issue](https://github.com/GoogleChromeLabs/web-audio-samples/issues/348) 12 | for details) 13 | 14 | 3. In the terminal, run `make` to build the WASM file. 15 | 16 | 4. Serve `index.html` file in the directoy. 17 | -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/wasm-supersaw/synth-processor.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | import Module from './synth.wasm.js'; 6 | import { FreeQueue } from '../../../lib/free-queue/free-queue.js'; 7 | 8 | /* global sampleRate */ 9 | 10 | // Web Audio API's render block size 11 | const NUM_FRAMES = 128; 12 | 13 | class SynthProcessor extends AudioWorkletProcessor { 14 | constructor() { 15 | super(); 16 | // Create an instance of Synthesizer and WASM memory helper. Then set up an 17 | // event handler for MIDI data from the main thread. 18 | this._synth = new Module.Synthesizer(sampleRate); 19 | this._wasmHeapBuffer = new FreeQueue(Module, NUM_FRAMES, 1, 1); 20 | this.port.onmessage = this._playTone.bind(this); 21 | } 22 | 23 | process(inputs, outputs) { 24 | // The output buffer (mono) provided by Web Audio API. 25 | const outputBuffer = outputs[0][0]; 26 | 27 | // Call the render function to write into the WASM buffer. Then clone the 28 | // rendered data in the first channel to process() callback's output 29 | // buffer. 30 | this._synth.render(this._wasmHeapBuffer.getHeapAddress(), NUM_FRAMES); 31 | outputBuffer.set(this._wasmHeapBuffer.getChannelData(0)); 32 | 33 | return true; 34 | } 35 | 36 | _playTone(event) { 37 | const isDown = event.data; 38 | isDown ? this._synth.noteOn(60) : this._synth.noteOff(60); 39 | } 40 | } 41 | 42 | registerProcessor('wasm-synth', SynthProcessor); 43 | -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/wasm-supersaw/synth_src/ChannelContext.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef OBOE_SYNTH_CHANNEL_CONTEXT_H 18 | #define OBOE_SYNTH_CHANNEL_CONTEXT_H 19 | 20 | #include 21 | #include "SynthMark.h" 22 | 23 | class ChannelContext 24 | { 25 | public: 26 | /** 27 | * Set channel bend using the raw 14-bit number extracted from a MIDI message. 28 | * @param bend14 29 | */ 30 | void setMidiBend(int bend14) { 31 | const int32_t offset = 1 << 13; 32 | int32_t centeredBend = bend14 - offset; 33 | mBendSemitones = mBendRange * centeredBend * (1.0f / offset); 34 | } 35 | 36 | /** 37 | * 38 | * @return channel bend in semitones 39 | */ 40 | synth_float_t getBend() { 41 | return mBendSemitones; 42 | } 43 | 44 | private: 45 | synth_float_t mBendRange = 2.0f; // pitch offset 46 | synth_float_t mBendSemitones = 0.0f; // pitch offset 47 | }; 48 | #endif //OBOE_SYNTH_CHANNEL_CONTEXT_H 49 | -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/wasm-supersaw/synth_src/PitchToFrequency.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "PitchToFrequency.h" 18 | 19 | PowerOfTwoTable PitchToFrequency::mPowerTable(64); 20 | -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/wasm-supersaw/synth_src/SineOscillator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * This code was translated from the JSyn Java code. 17 | * JSyn is Copyright 2009 Phil Burk, Mobileer Inc 18 | * JSyn is licensed under the Apache License, Version 2.0 19 | */ 20 | 21 | #ifndef SYNTHMARK_SINE_OSCILLATOR_H 22 | #define SYNTHMARK_SINE_OSCILLATOR_H 23 | 24 | #include 25 | #include "SynthMark.h" 26 | #include "SynthTools.h" 27 | 28 | class SineOscillator : public SawtoothOscillator 29 | { 30 | public: 31 | SineOscillator() 32 | : SawtoothOscillator() {} 33 | 34 | virtual ~SineOscillator() = default; 35 | 36 | virtual inline synth_float_t translatePhase(synth_float_t phase, synth_float_t phaseIncrement) { 37 | (void) phaseIncrement; 38 | return SynthTools::fastSine(phase * M_PI); 39 | } 40 | 41 | }; 42 | 43 | #endif // SYNTHMARK_SINE_OSCILLATOR_H 44 | -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/wasm-supersaw/synth_src/UnitGenerator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "UnitGenerator.h" 18 | 19 | int32_t UnitGenerator::mSampleRate = SYNTHMARK_SAMPLE_RATE; 20 | synth_float_t UnitGenerator::mSamplePeriod = 1.0f / SYNTHMARK_SAMPLE_RATE; 21 | -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/wasm/Makefile: -------------------------------------------------------------------------------- 1 | DEPS = SimpleKernel.cc 2 | 3 | build: $(DEPS) 4 | @emcc --bind -O2 \ 5 | -s WASM=1 \ 6 | -s WASM_ASYNC_COMPILATION=0 \ 7 | -s SINGLE_FILE=1 \ 8 | SimpleKernel.cc \ 9 | -o simple-kernel.wasmmodule.js \ 10 | -s MODULARIZE=1 \ 11 | -s EXPORT_ES6=1 \ 12 | -s EXPORTED_FUNCTIONS="['_malloc']" 13 | 14 | clean: 15 | @rm -f simple-kernel.wasmmodule.js -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/wasm/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: audio-worklet-and-web-assembly 4 | title: Audio Worklet and WebAssembly 5 | parent: audio-worklet 6 | to_root_dir: ../../../ 7 | --- 8 | 9 | {% extends to_root_dir + "_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |

{{ eleventyNavigation.title }}

14 |

A basic pattern to use Audio Worklet with WebAssembly. The 15 | AudioWorkletProcessor simply bypasses (copies) the audio via the WebAssembly 16 | function.

17 |

See 18 | Chrome Developers Article: Audio Worklet Design Pattern 20 | for more details.

21 | 22 |
23 | 24 | {% include to_root_dir + "_includes/example-source-code.njk" %} 25 |
26 | 27 | 28 | 29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /src/audio-worklet/design-pattern/wasm/main.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const audioContext = new AudioContext(); 6 | 7 | const startAudio = async (context) => { 8 | await context.audioWorklet.addModule('wasm-worklet-processor.js'); 9 | const oscillator = new OscillatorNode(context); 10 | const bypasser = new AudioWorkletNode(context, 'wasm-worklet-processor'); 11 | oscillator.connect(bypasser).connect(context.destination); 12 | oscillator.start(); 13 | }; 14 | 15 | // A simple onLoad handler. It also handles user gesture to unlock the audio 16 | // playback. 17 | window.addEventListener('load', async () => { 18 | const buttonEl = document.getElementById('button-start'); 19 | buttonEl.disabled = false; 20 | buttonEl.addEventListener('click', async () => { 21 | await startAudio(audioContext); 22 | audioContext.resume(); 23 | buttonEl.disabled = true; 24 | buttonEl.textContent = 'Playing...'; 25 | }, false); 26 | }); 27 | -------------------------------------------------------------------------------- /src/audio-worklet/free-queue/README.md: -------------------------------------------------------------------------------- 1 | # Free Queue 2 | 3 | A lock-free ring buffer implementation for high-performance audio processing 4 | designed to be used on top of the Web Audio API. 5 | 6 | It is based on the single-producer and single-consumer concept, so it can ensure 7 | thread safe concurrency without locks and mutexes, when the following conditions 8 | are satisfied - 9 | 1. There is only one producer, that is only one thread/worker is pushing data 10 | into the buffer. 11 | 2. There is only one consumer, that is only one thread/worker is pulling data 12 | out of the buffer. 13 | 14 | ## API 15 | 16 | ```ts 17 | // Constructor 18 | FreeQueue(size: number, channelCount: number = 1) 19 | // push data into FreeQueue. 20 | // returns true if pushing data is successful otherwise returns false 21 | push(input: Float32Array[], blockLength: number): boolean 22 | // pull data out of FreeQueue 23 | // returns true if pulling data is successful otherwise returns false 24 | pull(input: Float32Array[], blockLength: number): boolean 25 | // returns length of backing buffer 26 | getBufferLength(): number 27 | // returns if frame of given size is available 28 | isFrameAvailable(size: number): boolean 29 | ``` 30 | 31 | ## How it works 32 | 33 | This library can be used between two JavaScript Workers or can be used 34 | with WebAssembly. To use WebAssembly with programming languages like C/C++, 35 | an interface can be used to push and pull data from the buffer. 36 | See interface/README.md. 37 | -------------------------------------------------------------------------------- /src/audio-worklet/free-queue/examples/simple-passthrough/constants.js: -------------------------------------------------------------------------------- 1 | export const KERNEL_LENGTH = 20; 2 | export const RENDER_QUANTUM = 128; 3 | export const FRAME_SIZE = KERNEL_LENGTH * RENDER_QUANTUM; 4 | export const QUEUE_SIZE = 4096; 5 | -------------------------------------------------------------------------------- /src/audio-worklet/free-queue/examples/simple-passthrough/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: simple-passthrough 4 | title: Simple Passthrough Example 5 | parent: audio-worklet 6 | to_root_dir: ../../../../ 7 | --- 8 | 9 | {% extends to_root_dir + "_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 | 14 | 15 |

{{ eleventyNavigation.title }}

16 |

This example demonstrates how to take advantage of Worker thread and 17 | FreeQueue in conjunction with AudioWorklet. FreeQueue is being used here to 18 | exchange data between AudioWorklet and Worker thread. 19 |

20 |

See 21 | Chrome Developers Article: Audio Worklet Design Pattern 23 | for more details.

24 | 25 |
26 | 27 | {% include to_root_dir + "_includes/example-source-code.njk" %} 28 |
29 | 30 | 31 | 32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /src/audio-worklet/free-queue/examples/simple-passthrough/worker.js: -------------------------------------------------------------------------------- 1 | import { FreeQueueSAB } from "../../../../lib/free-queue/free-queue-sab.js"; 2 | import { FRAME_SIZE } from "./constants.js"; 3 | 4 | /** 5 | * Worker message event handler. 6 | * This will initialize worker with FreeQueue instance and set loop for audio 7 | * processing. 8 | */ 9 | self.onmessage = (msg) => { 10 | if (msg.data.type === "init") { 11 | let { inputQueue, outputQueue, atomicState } = msg.data.data; 12 | Object.setPrototypeOf(inputQueue, FreeQueueSAB.prototype); 13 | Object.setPrototypeOf(outputQueue, FreeQueueSAB.prototype); 14 | 15 | // buffer for storing data pulled out from queue. 16 | const input = new Float32Array(FRAME_SIZE); 17 | // loop for processing data. 18 | while (Atomics.wait(atomicState, 0, 0) === 'ok') { 19 | 20 | // pull data out from inputQueue. 21 | const didPull = inputQueue.pull([input], FRAME_SIZE); 22 | 23 | if (didPull) { 24 | // If pulling data out was successfull, process it and push it to 25 | // outputQueue 26 | const output = input.map(sample => 0.1 * sample); 27 | outputQueue.push([output], FRAME_SIZE); 28 | } 29 | 30 | Atomics.store(atomicState, 0, 0); 31 | } 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/audio-worklet/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: audio-worklet 4 | title: AudioWorklet 5 | parent: landing 6 | to_root_dir: ../ 7 | --- 8 | 9 | {% extends "../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |
14 |

AudioWorklet

15 |

Code examples and resources for 16 | 17 | AudioWorklet.

18 |
19 | 20 | {% for section in audioworklet_data %} 21 |
22 |

23 | {{ section.title }} 24 |

25 |
26 | {% for entry in section.entries %} 27 |
28 | 29 | {{ entry.title }} 30 | 31 |

{{ entry.description }}

32 |
33 | {% endfor %} 34 |
35 |
36 | {% endfor %} 37 | 38 | {% endblock %} 39 | -------------------------------------------------------------------------------- /src/audio-worklet/migration/spn-recorder/README.md: -------------------------------------------------------------------------------- 1 | # Recorder Demo using ScriptProcessorNode 2 | This demonstrates a basic recording app using ScriptProcessorNode. -------------------------------------------------------------------------------- /src/audio-worklet/migration/worklet-recorder/README.md: -------------------------------------------------------------------------------- 1 | # Audio Worklet Recording Demo 2 | 3 | This demonstrates a basic recording app using Audio Worklet. -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/DrumCell.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | /** 17 | * An abstraction of the one-shot sampler 18 | * 19 | * @class DrumCell 20 | */ 21 | class DrumCell { 22 | /** 23 | * Creates an instance of DrumCell with two required arguments. 24 | * 25 | * @param {Audionode} outputNode The outgoing AudioNode 26 | * @param {AudioBuffer} audioBuffer An AudioBuffer to be played 27 | * @memberof DrumCell 28 | */ 29 | constructor(outputNode, audioBuffer) { 30 | this._context = outputNode.context; 31 | this._buffer = audioBuffer; 32 | this._outputNode = outputNode; 33 | } 34 | 35 | /** 36 | * Plays the assigned buffer when called. 37 | * 38 | * @memberof DrumCell 39 | */ 40 | playSample() { 41 | const bufferSource = 42 | new AudioBufferSourceNode(this._context, {buffer: this._buffer}); 43 | const amp = new GainNode(this._context); 44 | bufferSource.connect(amp).connect(this._outputNode); 45 | bufferSource.start(); 46 | } 47 | } 48 | 49 | export default DrumCell; 50 | -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/README.md: -------------------------------------------------------------------------------- 1 | NOTE: This code example is for a Korean tutorial of "Web Audio API 드럼머신 만들기". 2 | For more information, see the 3 | [blog post](https://developer.chrome.com/blog/mother-language-day-2021/) about 4 | International Mother Language Day 2021 from Chrome Developers. 5 | 6 | # Web Audio API 드럼머신 만들기 7 | 8 | [라이브 데모](https://googlechromelabs.github.io/web-audio-samples/demos/mld-drum-sampler/) 9 | 10 | 데모의 정상적인 사용을 위해서는 샘플 파일들이 필요하며, 튜토리얼 비디오에 사용된 오디오 샘플들은 11 | [이 곳](https://github.com/GoogleChromeLabs/web-audio-samples/tree/main/src/demos/mld-drum-sampler) 12 | 에서 다운로드 할 수 있습니다. 13 | 14 | 로컬 웹서버에서의 실험을 위해서는 이 리포지터리를 `git clone`으로 내려받아 사용하는 것을 추천합니다. 15 | 16 | 사용에 문제 혹은 문의 사항이 있을 경우 17 | [이슈 트랙커](https://github.com/GoogleChromeLabs/web-audio-samples/issues)에 의견을 18 | 남겨주세요. 19 | -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: mld-drum-sampler 4 | title: Web Audio API 드럼머신 만들기 5 | parent: landing 6 | to_root_dir: ../../ 7 | --- 8 | 9 | {% extends "../../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |
14 |

Web Audio API 드럼머신 만들기

15 |

Web Audio API 16 | 와 File System 17 | Access API로 만들어 보는 간단한 드럼머신 예제. 18 | 19 | "2021 모국어의 날" 특집으로 제작된 한글 튜토리얼 입니다. 이 데모의 정상적인 사용을 위해서는 20 | 오디오 파일들이 필요하며, 21 | 22 | 튜토리얼 비디오에 사용된 오디오 파일들은 23 | 24 | 이 곳에서 다운로드 할 수 있습니다.

25 |

NOTE: This code example is for a Korean tutorial of "Web Audio API 드럼머신 26 | 만들기". For more information, see the Chrome Developers 27 | blog 28 | post about International Mother Language Day 2021.

29 |
30 | 31 |
32 |

아래 버튼을 누르고 오디오 파일들이 포함된 로컬 디렉토리를 선택해주세요. 파일 로딩이 완료되면 33 | 키보드를 사용하여 드럼 사운드를 연주할 수 있습니다.

34 | 35 |
36 | 37 | 38 | 39 | {% endblock %} 40 | -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/samples/drum-fx-01.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/mld-drum-sampler/samples/drum-fx-01.mp3 -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/samples/drum-fx-02.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/mld-drum-sampler/samples/drum-fx-02.mp3 -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/samples/drum-hh-01.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/mld-drum-sampler/samples/drum-hh-01.mp3 -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/samples/drum-hh-02.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/mld-drum-sampler/samples/drum-hh-02.mp3 -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/samples/drum-kd-01.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/mld-drum-sampler/samples/drum-kd-01.mp3 -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/samples/drum-kd-02.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/mld-drum-sampler/samples/drum-kd-02.mp3 -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/samples/drum-oh-01.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/mld-drum-sampler/samples/drum-oh-01.mp3 -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/samples/drum-oh-02.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/mld-drum-sampler/samples/drum-oh-02.mp3 -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/samples/drum-perc-01.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/mld-drum-sampler/samples/drum-perc-01.mp3 -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/samples/drum-perc-02.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/mld-drum-sampler/samples/drum-perc-02.mp3 -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/samples/drum-sd-01.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/mld-drum-sampler/samples/drum-sd-01.mp3 -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/samples/drum-sd-02.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/mld-drum-sampler/samples/drum-sd-02.mp3 -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/samples/ir-hall.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/mld-drum-sampler/samples/ir-hall.mp3 -------------------------------------------------------------------------------- /src/demos/mld-drum-sampler/samples/samples.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/mld-drum-sampler/samples/samples.zip -------------------------------------------------------------------------------- /src/demos/panning-reverberation/simple.css: -------------------------------------------------------------------------------- 1 | body {background:#eed;} 2 | h1 {color:#111;} 3 | a {color:blue; text-decoration:none; font-size:125%} 4 | #canvasID {background:#fff;} 5 | #canvasElevationID {background:#fff;} 6 | .bigList {color:blue; font-size:large; font-weight:bold} 7 | .smallList {color:blue; font-size:medium; font-weight:bold} 8 | -------------------------------------------------------------------------------- /src/demos/pool/images/poolballs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/pool/images/poolballs.png -------------------------------------------------------------------------------- /src/demos/pwa-audio-recorder/README.md: -------------------------------------------------------------------------------- 1 | # Audio Recorder 2 | 3 | A simple, responsive, progressive web application that records audio clips using the 4 | device's microphone. 5 | 6 | The user interface is built with [Material Components Web](https://material.io/develop/web). 7 | The audio is recorded with the [MediaStream Recording API](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream_Recording_API) 8 | and visualized with an [AnalyserNode](https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode). 9 | 10 | ## Contributing 11 | 12 | This web application is intentionally simple and does not rely on a build step 13 | of any sort. 14 | -------------------------------------------------------------------------------- /src/demos/pwa-audio-recorder/icons/android-chrome-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/pwa-audio-recorder/icons/android-chrome-192.png -------------------------------------------------------------------------------- /src/demos/pwa-audio-recorder/icons/android-chrome-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/pwa-audio-recorder/icons/android-chrome-512.png -------------------------------------------------------------------------------- /src/demos/pwa-audio-recorder/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/pwa-audio-recorder/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /src/demos/pwa-audio-recorder/icons/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/pwa-audio-recorder/icons/favicon.png -------------------------------------------------------------------------------- /src/demos/pwa-audio-recorder/icons/maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/pwa-audio-recorder/icons/maskable-192.png -------------------------------------------------------------------------------- /src/demos/pwa-audio-recorder/icons/maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/pwa-audio-recorder/icons/maskable-512.png -------------------------------------------------------------------------------- /src/demos/pwa-audio-recorder/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Audio Recorder", 3 | "short_name": "Recorder", 4 | "theme_color": "#d32f2f", 5 | "background_color": "#f5f5f6", 6 | "display": "standalone", 7 | "icons": [ 8 | { 9 | "src": "icons/android-chrome-192.png", 10 | "sizes": "192x192", 11 | "type": "image/png" 12 | }, 13 | { 14 | "src": "icons/apple-touch-icon.png", 15 | "sizes": "180x180", 16 | "type": "image/png" 17 | }, 18 | { 19 | "src": "icons/android-chrome-512.png", 20 | "sizes": "512x512", 21 | "type": "image/png" 22 | }, 23 | { 24 | "src": "icons/maskable-192.png", 25 | "sizes": "192x192", 26 | "type": "image/png", 27 | "purpose": "maskable" 28 | }, 29 | { 30 | "src": "icons/maskable-512.png", 31 | "sizes": "512x512", 32 | "type": "image/png", 33 | "purpose": "maskable" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /src/demos/pwa-audio-recorder/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background-color: #f5f5f6; 4 | --mdc-theme-primary: #d32f2f; 5 | } 6 | 7 | .sound-clips { 8 | display: flex; 9 | flex-direction: column; 10 | row-gap: 1em; 11 | margin: 2em; 12 | } 13 | 14 | .clip { 15 | display: flex; 16 | overflow: hidden; 17 | } 18 | 19 | .clip audio { 20 | flex-grow: 1; 21 | } 22 | 23 | .clip canvas { 24 | display: none; 25 | } 26 | 27 | .clip.clip-recording canvas { 28 | display: block; 29 | } 30 | 31 | .clip-recording .recording-invisible { 32 | display: none; 33 | } 34 | 35 | /* Hide empty state as soon as the first sound clip is added to .sound-clips. */ 36 | .sound-clips > * ~ .empty { 37 | display: none; 38 | } 39 | 40 | .empty { 41 | text-align: center; 42 | opacity: 0.2; 43 | margin-top: 4em; 44 | } 45 | 46 | .empty .material-icons { 47 | font-size: 10em; 48 | } 49 | 50 | #record-outline { 51 | position: fixed; 52 | bottom: 2em; 53 | left: 50%; 54 | transform: translateX(-50%); 55 | border-radius: 50%; 56 | } 57 | 58 | .mdc-fab { 59 | background-color: var(--mdc-theme-primary); 60 | } 61 | 62 | .mdc-top-app-bar__title { 63 | padding: 0; 64 | } 65 | 66 | .logo { 67 | padding: 0 5px 0 20px; 68 | } 69 | 70 | audio::-webkit-media-controls-enclosure { 71 | background: none; 72 | } 73 | -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/LED_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/LED_off.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/LED_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/LED_on.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_cancel.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_demo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_demo1.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_demo1_loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_demo1_loading.gif -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_demo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_demo2.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_demo2_loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_demo2_loading.gif -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_demo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_demo3.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_demo3_loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_demo3_loading.gif -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_demo4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_demo4.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_demo4_loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_demo4_loading.gif -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_demo5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_demo5.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_demo5_loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_demo5_loading.gif -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_load.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_ok.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_play.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_play_loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_play_loading.gif -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_reset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_reset.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_save.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/btn_stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/btn_stop.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/button_half.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/button_half.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/button_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/button_off.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/button_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/button_on.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/drop_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/drop_arrow.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/slider_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/slider_thumb.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/slider_track.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/slider_track.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/sliderh_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/sliderh_thumb.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/sliderh_track.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/sliderh_track.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/tempo_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/tempo_bg.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/tempo_dec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/tempo_dec.png -------------------------------------------------------------------------------- /src/demos/shiny-drum-machine/images/tempo_inc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/shiny-drum-machine/images/tempo_inc.png -------------------------------------------------------------------------------- /src/demos/stress-box/assets/style.css: -------------------------------------------------------------------------------- 1 | canvas { 2 | padding: 0; 3 | margin: 0; 4 | background-color: #333388; 5 | user-select: none; 6 | } 7 | 8 | .log { 9 | font-family: monospace; 10 | font-size: 13px; 11 | margin-bottom: 20px; 12 | } 13 | -------------------------------------------------------------------------------- /src/demos/stress-box/js/lib.js: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /** 6 | * @fileOverview Utility collection for stress testing. 7 | */ 8 | 9 | const Lib = { 10 | 11 | getSystemInfo: () => { 12 | let ua = navigator.userAgent; 13 | let M = ua.match( 14 | /(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*([\d\.]+)/i) || 15 | []; 16 | let tem; 17 | if (/trident/i.test(M[1])) { 18 | tem = /\brv[ :]+(\d+)/g.exec(ua) || []; 19 | return {name:'IE', version: (tem[1] || '')}; 20 | } 21 | if (M[1] === 'Chrome') { 22 | tem = ua.match(/\bOPR|Edge\/(\d+)/) 23 | if(tem != null) { 24 | return {name: 'Opera', version: tem[1]}; 25 | } 26 | } 27 | M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?']; 28 | if((tem = ua.match(/version\/([\d.]+)/i)) != null) { 29 | M.splice(1, 1, tem[1]); 30 | } 31 | return { 32 | name: M[0], 33 | version: M[1] 34 | }; 35 | }, 36 | 37 | getLoadingTime: () => { 38 | let timingInfo = performance.timing; 39 | return timingInfo.loadEventStart - timingInfo.navigationStart; 40 | }, 41 | 42 | maybe: () => { 43 | return Math.random() < 0.5; 44 | }, 45 | 46 | getMousePosition: (element, clickEvent) => { 47 | let rect = element.getBoundingClientRect(); 48 | return { 49 | x: clickEvent.clientX - rect.left, 50 | y: clickEvent.clientY - rect.top 51 | }; 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /src/demos/stress-box/js/stack.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [stack description] 3 | * @type {Object} 4 | */ 5 | demos.stack = {}; 6 | 7 | 8 | /** 9 | * [initWorld description] 10 | * @param {[type]} world [description] 11 | * @return {[type]} [description] 12 | */ 13 | demos.stack.initWorld = function (world) { 14 | let sd = new b2BoxDef(); 15 | let bd = new b2BodyDef(); 16 | bd.AddShape(sd); 17 | sd.density = 1.0; 18 | sd.friction = 0.5; 19 | sd.extents.Set(10, 10); 20 | 21 | let i; 22 | for (i = 0; i < 8; i++) { 23 | bd.position.Set(500/2-Math.random()*2-1, (250-5-i*22)); 24 | world.CreateBody(bd); 25 | } 26 | for (i = 0; i < 8; i++) { 27 | bd.position.Set(500/2-100-Math.random()*5+i, (250-5-i*22)); 28 | world.CreateBody(bd); 29 | } 30 | for (i = 0; i < 8; i++) { 31 | bd.position.Set(500/2+100+Math.random()*5-i, (250-5-i*22)); 32 | world.CreateBody(bd); 33 | } 34 | } 35 | 36 | 37 | /** 38 | * 39 | */ 40 | demos.InitWorlds.push(demos.stack.initWorld); 41 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/collision/ClipVertex.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | 22 | 23 | var ClipVertex = Class.create(); 24 | ClipVertex.prototype = 25 | { 26 | v: new b2Vec2(), 27 | id: new b2ContactID(), 28 | initialize: function() { 29 | // initialize instance variables for references 30 | this.v = new b2Vec2(); 31 | this.id = new b2ContactID(); 32 | // 33 | }}; 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/collision/b2Bound.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | var b2Bound = Class.create(); 22 | b2Bound.prototype = { 23 | IsLower: function(){ return (this.value & 1) == 0; }, 24 | IsUpper: function(){ return (this.value & 1) == 1; }, 25 | Swap: function(b){ 26 | var tempValue = this.value; 27 | var tempProxyId = this.proxyId; 28 | var tempStabbingCount = this.stabbingCount; 29 | 30 | this.value = b.value; 31 | this.proxyId = b.proxyId; 32 | this.stabbingCount = b.stabbingCount; 33 | 34 | b.value = tempValue; 35 | b.proxyId = tempProxyId; 36 | b.stabbingCount = tempStabbingCount; 37 | }, 38 | 39 | value: 0, 40 | proxyId: 0, 41 | stabbingCount: 0, 42 | 43 | initialize: function() {}} 44 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/collision/b2BoundValues.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | var b2BoundValues = Class.create(); 22 | b2BoundValues.prototype = { 23 | lowerValues: [0,0], 24 | upperValues: [0,0], 25 | 26 | initialize: function() { 27 | // initialize instance variables for references 28 | this.lowerValues = [0,0]; 29 | this.upperValues = [0,0]; 30 | // 31 | }} 32 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/collision/b2BufferedPair.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | var b2BufferedPair = Class.create(); 22 | b2BufferedPair.prototype = { 23 | proxyId1: 0, 24 | proxyId2: 0, 25 | 26 | initialize: function() {}} 27 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/collision/b2ContactPoint.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | // We use contact ids to facilitate warm starting. 22 | var b2ContactPoint = Class.create(); 23 | b2ContactPoint.prototype = 24 | { 25 | position: new b2Vec2(), 26 | separation: null, 27 | normalImpulse: null, 28 | tangentImpulse: null, 29 | id: new b2ContactID(), 30 | initialize: function() { 31 | // initialize instance variables for references 32 | this.position = new b2Vec2(); 33 | this.id = new b2ContactID(); 34 | // 35 | }}; 36 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/collision/b2Manifold.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | // A manifold for two touching convex shapes. 22 | var b2Manifold = Class.create(); 23 | b2Manifold.prototype = 24 | { 25 | initialize: function(){ 26 | this.points = new Array(b2Settings.b2_maxManifoldPoints); 27 | for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++){ 28 | this.points[i] = new b2ContactPoint(); 29 | } 30 | this.normal = new b2Vec2(); 31 | }, 32 | points: null, 33 | normal: null, 34 | pointCount: 0}; 35 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/collision/b2OBB.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | // A manifold for two touching convex shapes. 22 | var b2OBB = Class.create(); 23 | b2OBB.prototype = 24 | { 25 | R: new b2Mat22(), 26 | center: new b2Vec2(), 27 | extents: new b2Vec2(), 28 | initialize: function() { 29 | // initialize instance variables for references 30 | this.R = new b2Mat22(); 31 | this.center = new b2Vec2(); 32 | this.extents = new b2Vec2(); 33 | // 34 | }}; 35 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/collision/b2PairCallback.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | var b2PairCallback = Class.create(); 22 | b2PairCallback.prototype = 23 | { 24 | //virtual ~b2PairCallback() {} 25 | 26 | // This returns the new pair user data. 27 | PairAdded: function(proxyUserData1, proxyUserData2){return null}, 28 | 29 | // This should free the pair's user data. In extreme circumstances, it is possible 30 | // this will be called with null pairUserData because the pair never existed. 31 | PairRemoved: function(proxyUserData1, proxyUserData2, pairUserData){}, 32 | initialize: function() {}}; 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/collision/b2Proxy.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | var b2Proxy = Class.create(); 22 | b2Proxy.prototype = { 23 | GetNext: function(){ return this.lowerBounds[0]; }, 24 | SetNext: function(next) { this.lowerBounds[0] = next /*& 0x0000ffff*/; }, 25 | 26 | IsValid: function(){ return this.overlapCount != b2BroadPhase.b2_invalid; }, 27 | 28 | lowerBounds: [/*uint*/(0), /*uint*/(0)], 29 | upperBounds: [/*uint*/(0), /*uint*/(0)], 30 | overlapCount: 0, 31 | timeStamp: 0, 32 | 33 | userData: null, 34 | 35 | initialize: function() { 36 | // initialize instance variables for references 37 | this.lowerBounds = [/*uint*/(0), /*uint*/(0)]; 38 | this.upperBounds = [/*uint*/(0), /*uint*/(0)]; 39 | // 40 | }} 41 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/collision/shapes/b2MassData.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | var b2MassData = Class.create(); 26 | b2MassData.prototype = 27 | { 28 | mass: 0.0, 29 | center: new b2Vec2(0,0), 30 | I: 0.0, 31 | 32 | initialize: function() { 33 | // initialize instance variables for references 34 | this.center = new b2Vec2(0,0); 35 | // 36 | }} 37 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/dynamics/b2CollisionFilter.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | var b2CollisionFilter = Class.create(); 26 | b2CollisionFilter.prototype = 27 | { 28 | 29 | // Return true if contact calculations should be performed between these two shapes. 30 | ShouldCollide: function(shape1, shape2){ 31 | if (shape1.m_groupIndex == shape2.m_groupIndex && shape1.m_groupIndex != 0) 32 | { 33 | return shape1.m_groupIndex > 0; 34 | } 35 | 36 | var collide = (shape1.m_maskBits & shape2.m_categoryBits) != 0 && (shape1.m_categoryBits & shape2.m_maskBits) != 0; 37 | return collide; 38 | }, 39 | 40 | 41 | initialize: function() {}}; 42 | b2CollisionFilter.b2_defaultFilter = new b2CollisionFilter; 43 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/dynamics/b2TimeStep.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | var b2TimeStep = Class.create(); 22 | b2TimeStep.prototype = 23 | { 24 | dt: null, 25 | inv_dt: null, 26 | iterations: 0, 27 | initialize: function() {}}; 28 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/dynamics/contacts/b2ContactConstraint.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | 22 | 23 | var b2ContactConstraint = Class.create(); 24 | b2ContactConstraint.prototype = 25 | { 26 | initialize: function(){ 27 | // initialize instance variables for references 28 | this.normal = new b2Vec2(); 29 | // 30 | 31 | this.points = new Array(b2Settings.b2_maxManifoldPoints); 32 | for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++){ 33 | this.points[i] = new b2ContactConstraintPoint(); 34 | } 35 | 36 | 37 | }, 38 | points: null, 39 | normal: new b2Vec2(), 40 | manifold: null, 41 | body1: null, 42 | body2: null, 43 | friction: null, 44 | restitution: null, 45 | pointCount: 0}; 46 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/dynamics/contacts/b2ContactConstraintPoint.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | 22 | 23 | var b2ContactConstraintPoint = Class.create(); 24 | b2ContactConstraintPoint.prototype = 25 | { 26 | localAnchor1: new b2Vec2(), 27 | localAnchor2: new b2Vec2(), 28 | normalImpulse: null, 29 | tangentImpulse: null, 30 | positionImpulse: null, 31 | normalMass: null, 32 | tangentMass: null, 33 | separation: null, 34 | velocityBias: null, 35 | initialize: function() { 36 | // initialize instance variables for references 37 | this.localAnchor1 = new b2Vec2(); 38 | this.localAnchor2 = new b2Vec2(); 39 | // 40 | }}; 41 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/dynamics/contacts/b2ContactNode.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | 22 | 23 | var b2ContactNode = Class.create(); 24 | b2ContactNode.prototype = 25 | { 26 | other: null, 27 | contact: null, 28 | prev: null, 29 | next: null, 30 | initialize: function() {}}; 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/dynamics/contacts/b2ContactRegister.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | var b2ContactRegister = Class.create(); 22 | b2ContactRegister.prototype = 23 | { 24 | createFcn: null, 25 | destroyFcn: null, 26 | primary: null, 27 | initialize: function() {}}; 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/dynamics/joints/b2JointDef.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | 22 | 23 | var b2JointDef = Class.create(); 24 | b2JointDef.prototype = 25 | { 26 | 27 | initialize: function() 28 | { 29 | this.type = b2Joint.e_unknownJoint; 30 | this.userData = null; 31 | this.body1 = null; 32 | this.body2 = null; 33 | this.collideConnected = false; 34 | }, 35 | 36 | type: 0, 37 | userData: null, 38 | body1: null, 39 | body2: null, 40 | collideConnected: null} 41 | -------------------------------------------------------------------------------- /src/demos/stress-box/third-party/box2d/dynamics/joints/b2JointNode.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http: 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked, and must not be 15 | * misrepresented the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | 20 | 21 | 22 | 23 | var b2JointNode = Class.create(); 24 | b2JointNode.prototype = 25 | { 26 | 27 | other: null, 28 | joint: null, 29 | prev: null, 30 | next: null, 31 | 32 | 33 | initialize: function() {}} 34 | -------------------------------------------------------------------------------- /src/demos/visualizer/shaders/common-vertex.shader: -------------------------------------------------------------------------------- 1 | // The common vertex shader used for the frequency and sonogram visualizations 2 | attribute vec3 gPosition; 3 | attribute vec2 gTexCoord0; 4 | 5 | varying vec2 texCoord; 6 | 7 | void main() 8 | { 9 | gl_Position = vec4(gPosition.x, gPosition.y, gPosition.z, 1.0); 10 | texCoord = gTexCoord0; 11 | } 12 | -------------------------------------------------------------------------------- /src/demos/visualizer/shaders/frequency-fragment.shader: -------------------------------------------------------------------------------- 1 | // Frequency fragment shader 2 | #ifdef GL_ES 3 | precision mediump float; 4 | #endif 5 | 6 | varying vec2 texCoord; 7 | uniform sampler2D frequencyData; 8 | uniform vec4 foregroundColor; 9 | uniform vec4 backgroundColor; 10 | uniform float yoffset; 11 | 12 | void main() 13 | { 14 | vec4 sample = texture2D(frequencyData, vec2(texCoord.x, yoffset)); 15 | if (texCoord.y > sample.a) { 16 | // if (texCoord.y > sample.a + 1 || texCoord.y < sample.a - 1) { 17 | discard; 18 | } 19 | float x = texCoord.y / sample.a; 20 | x = x * x * x; 21 | gl_FragColor = mix(foregroundColor, backgroundColor, x); 22 | } 23 | -------------------------------------------------------------------------------- /src/demos/visualizer/shaders/sonogram-fragment.shader: -------------------------------------------------------------------------------- 1 | // Sonogram fragment shader 2 | #ifdef GL_ES 3 | precision mediump float; 4 | #endif 5 | 6 | varying vec2 texCoord; 7 | 8 | uniform sampler2D frequencyData; 9 | uniform vec4 foregroundColor; 10 | uniform vec4 backgroundColor; 11 | uniform float yoffset; 12 | 13 | void main() 14 | { 15 | float x = pow(256.0, texCoord.x - 1.0); 16 | float y = texCoord.y + yoffset; 17 | 18 | vec4 sample = texture2D(frequencyData, vec2(x, y)); 19 | float k = sample.a; 20 | 21 | // gl_FragColor = vec4(k, k, k, 1.0); 22 | // Fade out the mesh close to the edges 23 | float fade = pow(cos((1.0 - texCoord.y) * 0.5 * 3.1415926535), 0.5); 24 | k *= fade; 25 | vec4 color = k * vec4(0,0,0,1) + (1.0 - k) * backgroundColor; 26 | gl_FragColor = color; 27 | } 28 | -------------------------------------------------------------------------------- /src/demos/visualizer/shaders/sonogram-vertex.shader: -------------------------------------------------------------------------------- 1 | // The vertex shader used for the 3D sonogram visualization 2 | 3 | attribute vec3 gPosition; 4 | attribute vec2 gTexCoord0; 5 | uniform sampler2D vertexFrequencyData; 6 | uniform float vertexYOffset; 7 | uniform mat4 worldViewProjection; 8 | uniform float verticalScale; 9 | 10 | varying vec2 texCoord; 11 | 12 | void main() 13 | { 14 | float x = pow(256.0, gTexCoord0.x - 1.0); 15 | vec4 sample = texture2D(vertexFrequencyData, vec2(x, gTexCoord0.y + vertexYOffset)); 16 | vec4 newPosition = vec4(gPosition.x, gPosition.y + verticalScale * sample.a, gPosition.z, 1.0); 17 | gl_Position = worldViewProjection * newPosition; 18 | texCoord = gTexCoord0; 19 | } 20 | -------------------------------------------------------------------------------- /src/demos/visualizer/shaders/waveform-fragment.shader: -------------------------------------------------------------------------------- 1 | // Waveform fragment shader 2 | #ifdef GL_ES 3 | precision mediump float; 4 | #endif 5 | 6 | varying vec2 texCoord; 7 | uniform sampler2D frequencyData; 8 | uniform vec4 foregroundColor; 9 | uniform vec4 backgroundColor; 10 | uniform float yoffset; 11 | 12 | void main() 13 | { 14 | vec4 sample = texture2D(frequencyData, vec2(texCoord.x, yoffset)); 15 | if (texCoord.y > sample.a + 0.01 || texCoord.y < sample.a - 0.01) { 16 | discard; 17 | } 18 | float x = (texCoord.y - sample.a) / 0.01; 19 | x = x * x * x; 20 | gl_FragColor = mix(foregroundColor, backgroundColor, x); 21 | } 22 | -------------------------------------------------------------------------------- /src/demos/wavetable-synth-2/README.md: -------------------------------------------------------------------------------- 1 | # Local Development 2 | 3 | - `cd` to `wavetable-synth-2` directory. 4 | - Use `python3 -m http.server` for now. 5 | -------------------------------------------------------------------------------- /src/demos/wavetable-synth-2/sound/matrix-reverb6.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/wavetable-synth-2/sound/matrix-reverb6.wav -------------------------------------------------------------------------------- /src/demos/wavetable-synth-2/style/style.css: -------------------------------------------------------------------------------- 1 | /* For fonts */ 2 | body { 3 | font-family: 'Inter', sans-serif; 4 | font-optical-sizing: auto; 5 | font-weight: 400; 6 | font-style: normal; 7 | min-height: 100vh; 8 | color: #d1d5db; 9 | background-color: #30353a; 10 | } 11 | 12 | .header { 13 | display: flex; 14 | justify-content: center; 15 | align-items: center; 16 | padding: 20px; 17 | } 18 | 19 | .synth-container { 20 | display: flex; 21 | flex-direction: column; 22 | justify-content: center; 23 | align-items: center; 24 | font-family: sans-serif; 25 | gap: 20px; 26 | /* flex-wrap: wrap; Allow wrapping if needed */ 27 | padding: 20px; 28 | } 29 | 30 | .footer { 31 | font-size: small; 32 | display: flex; 33 | justify-content: center; 34 | align-items: center; 35 | padding: 20px; 36 | } 37 | 38 | knob-simple { 39 | width: 90px; /* Example width */ 40 | height: 120px; /* Example height */ 41 | } 42 | 43 | matrix-sequence-2d { 44 | /* Updated tag name */ 45 | display: block; /* Make it a block element */ 46 | width: 600px; /* Example width */ 47 | max-width: 600px; 48 | height: 300px; /* Example height */ 49 | border: 1px solid #ccc; 50 | cursor: crosshair; 51 | margin-bottom: 20px; 52 | touch-action: none; /* Prevent default touch actions like scrolling */ 53 | } 54 | -------------------------------------------------------------------------------- /src/demos/wavetable-synth/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/demos/wavetable-synth/images/loading.gif -------------------------------------------------------------------------------- /src/demos/wavetable-synth/lib/buffer-loader.js: -------------------------------------------------------------------------------- 1 | function BufferLoader(context, urlList, callback) { 2 | this.context = context; 3 | this.urlList = urlList; 4 | this.onload = callback; 5 | this.bufferList = new Array(); 6 | this.loadCount = 0; 7 | } 8 | 9 | BufferLoader.prototype.loadBuffer = function(url, index) { 10 | // Load buffer asynchronously 11 | var request = new XMLHttpRequest(); 12 | request.open("GET", url, true); 13 | request.responseType = "arraybuffer"; 14 | 15 | var loader = this; 16 | 17 | request.onload = function() { 18 | // Asynchronously decode the audio file data in request.response 19 | loader.context.decodeAudioData( 20 | request.response, function(buffer) { 21 | if (!buffer) { 22 | alert('error decoding file data: ' + url); 23 | return; 24 | } 25 | loader.bufferList[index] = buffer; 26 | if (++loader.loadCount == loader.urlList.length) loader.onload(loader.bufferList); 27 | }, function(error) { 28 | console.error('decodeAudioData error', error); 29 | }); 30 | } 31 | 32 | request.onerror = function() { 33 | alert('BufferLoader: XHR error'); 34 | } 35 | 36 | request.send(); 37 | } 38 | 39 | BufferLoader.prototype.load = function() { 40 | for (var i = 0; i < this.urlList.length; ++i) 41 | this.loadBuffer(this.urlList[i], i); 42 | } 43 | -------------------------------------------------------------------------------- /src/demos/wavetable-synth/lib/global-effects.js: -------------------------------------------------------------------------------- 1 | function GlobalEffects(context) { 2 | this.context = context; 3 | 4 | // Create dynamics compressor to sweeten the overall mix. 5 | var compressor = context.createDynamicsCompressor(); 6 | compressor.connect(context.destination); 7 | 8 | var convolver = context.createConvolver(); 9 | 10 | convolver.connect(compressor); 11 | 12 | // BPM delay through delayWaveShaper feedback loop 13 | var bpmDelay = new BpmDelay(context); 14 | 15 | bpmDelay.delay.connect(compressor); 16 | 17 | var delayFeedback = context.createGain(); 18 | delayFeedback.gain.value = 0.5; 19 | bpmDelay.delay.connect(delayFeedback); 20 | delayWaveShaper = new WaveShaper(context); 21 | 22 | delayFeedback.connect(delayWaveShaper.input); 23 | delayWaveShaper.output.connect(bpmDelay.delay); 24 | 25 | this.compressor = compressor; 26 | this.convolver = convolver; 27 | this.bpmDelay = bpmDelay; 28 | this.delayFeedback = delayFeedback; 29 | this.delayWaveShaper = delayWaveShaper; 30 | 31 | this.setDelayGrunge(4.0); 32 | } 33 | 34 | GlobalEffects.prototype.setDelayFeedback = function(x) { 35 | this.delayFeedback.gain.value = x; 36 | } 37 | 38 | GlobalEffects.prototype.setDelayGrunge = function(driveDb) { 39 | this.delayWaveShaper.setDrive(Math.pow(10, 0.05*driveDb)); 40 | } 41 | 42 | GlobalEffects.prototype.setConvolverBuffer = function(buffer) { 43 | this.convolver.buffer = buffer; 44 | } 45 | -------------------------------------------------------------------------------- /src/demos/wavetable-synth/simple.css: -------------------------------------------------------------------------------- 1 | body {background:#eed;} 2 | h1 {color:#111;} 3 | a {color:blue; text-decoration:none; font-size:125%} 4 | #canvasID {background:#fff;} 5 | #canvasElevationID {background:#fff;} 6 | .bigList {color:blue; font-size:large; font-weight:bold} 7 | .smallList {color:blue; font-size:medium; font-weight:bold} 8 | -------------------------------------------------------------------------------- /src/experiments/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: experiments 4 | title: Experiments 5 | parent: landing 6 | to_root_dir: ../ 7 | --- 8 | 9 | {% extends "../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |
14 |

Experiments

15 |

TODO: Experiments

16 |
17 | 18 | {% for section in experiments_data %} 19 |
20 |

21 | {{ section.title }} 22 |

23 |
24 | {% for entry in section.entries %} 25 |
26 | 27 | {{ entry.title }} 28 | 29 |

{{ entry.description }}

30 |
31 | {% endfor %} 32 |
33 |
34 | {% endfor %} 35 | 36 | {% endblock %} 37 | -------------------------------------------------------------------------------- /src/experiments/webgpuaudio/assets.js: -------------------------------------------------------------------------------- 1 | const IRDirPath = '../../sounds/impulse-responses/'; 2 | 3 | const Assets = [ 4 | { 5 | label: 'Ambisonic (256 samples)', 6 | path: IRDirPath + 'ambisonic-1o-ir.wav', 7 | }, 8 | { 9 | label: 'Cardioid', 10 | path: IRDirPath + 'cardiod-35-10-spread.wav', 11 | }, 12 | { 13 | label: 'Omni', 14 | path: IRDirPath + 'omni-35-10.wav', 15 | }, 16 | { 17 | label: 'Spatialized', 18 | path: IRDirPath + 'spatialized2.wav', 19 | }, 20 | { 21 | label: 'Test IR (10 samples)', 22 | path: 'TEST', 23 | } 24 | ]; 25 | 26 | export default Assets; 27 | -------------------------------------------------------------------------------- /src/experiments/webgpuaudio/constants.js: -------------------------------------------------------------------------------- 1 | // WebAudio's render block size (in sample-frames) 2 | export const RENDER_QUANTUM = 128; 3 | 4 | // The size multiplier for the batch processing frame size (in worker). 5 | export const KERNEL_LENGTH = 4; 6 | 7 | // The actual batch processing frame size used in Worker. 8 | export const FRAME_SIZE = KERNEL_LENGTH * RENDER_QUANTUM; 9 | 10 | // The maximum size of two SharedArrayBuffers between Worker and 11 | // AudioWorkletProcessor. 12 | export const QUEUE_SIZE = 2048; 13 | 14 | // WebGPU parallelization parameter 15 | export const WORKGROUP_SIZE = 4; 16 | -------------------------------------------------------------------------------- /src/experiments/webgpuaudio/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: webgpuaudio 4 | title: WebGPUAudio Experiment 5 | parent: experiments 6 | to_root_dir: ../../ 7 | --- 8 | 9 | {% extends "../../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 | 14 | 15 |

{{ eleventyNavigation.title }}

16 | 17 |

An experiment to use Web Audio API and WebGPU together to process audio 18 | stream with GPU.

19 | 20 |
21 | {# TODO: enable this dropdown when the app supports IR selection. #} 22 | {#
23 | 24 | 27 |
#} 28 |
29 | 30 |
31 | 32 | 33 | 34 | {% endblock %} 35 | -------------------------------------------------------------------------------- /src/experiments/webgpuaudio/style.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/experiments/webgpuaudio/style.css -------------------------------------------------------------------------------- /src/experiments/webgpuaudio/test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WebGPUAudio Tests 7 | 8 | 9 | 23 | 24 |

Please click on the test button below to run individual tests. Failures will show up in console

25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 41 | 42 |
Test NameStatus
32 | 33 | 35 |
36 | Not run. 37 | 38 | 39 |
40 |
43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: landing 4 | title: Home 5 | to_root_dir: ./ 6 | hide_header: true 7 | --- 8 | 9 | {% extends "./_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |
14 |

Web Audio/MIDI Samples

15 |

A collection of resources and examples for Web Audio/MIDI API. Curated by 16 | Chrome Web Audio Team.

17 |
18 | 19 | {% for section in landing_data %} 20 |
21 |

22 | {{ section.title }} 23 |

24 |
25 | {% for entry in section.entries %} 26 |
27 | 28 | {{ entry.title }} 29 | 30 |

{{ entry.description }}

31 |
32 | {% endfor %} 33 |
34 |
35 | {% endfor %} 36 | 37 | {% endblock %} 38 | -------------------------------------------------------------------------------- /src/rainfly/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "browser": true, 5 | "node": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:svelte/recommended", 10 | "google" 11 | ], 12 | "ignorePatterns": [ 13 | "build/", 14 | ".svelte-kit/", 15 | "dist/", 16 | "static/" 17 | ], 18 | "globals": { 19 | "window": "readonly", 20 | "document": "readonly" 21 | }, 22 | "parserOptions": { 23 | "ecmaVersion": 12, 24 | "sourceType": "module" 25 | }, 26 | "rules": {} 27 | } -------------------------------------------------------------------------------- /src/rainfly/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | # Output 4 | .output 5 | .vercel 6 | /.svelte-kit 7 | /build 8 | 9 | # OS 10 | .DS_Store 11 | Thumbs.db 12 | 13 | # Env 14 | .env 15 | .env.* 16 | !.env.example 17 | !.env.test 18 | 19 | # Vite 20 | vite.config.js.timestamp-* 21 | vite.config.ts.timestamp-* 22 | 23 | # IDE 24 | .idea 25 | .vscode 26 | 27 | # Lockfiles 28 | package-lock.json 29 | bun.lockb 30 | -------------------------------------------------------------------------------- /src/rainfly/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /src/rainfly/README.md: -------------------------------------------------------------------------------- 1 | # Rainfly 2 |
3 | Rainfly logo 4 |
5 | 6 | **An AudioWorklet DSP Playground for Chromium Web Audio API Project (2024)** 7 | 8 | ## Developing 9 | Install dependencies with `npm install` (or `pnpm install` or `yarn`), and then start a development server: 10 | 11 | ```bash 12 | npm run dev 13 | 14 | # or start the server and open the app in a new browser tab 15 | npm run dev -- --open 16 | ``` 17 | 18 | ## Building 19 | 20 | To create a production version of Rainfly: 21 | 22 | ```bash 23 | npm run build 24 | ``` 25 | 26 | You can preview the production build with `npm run preview`. 27 | 28 | ## Using Parameters in Rainfly Examples 29 | 30 | Rainfly supports defining parameters inside comments, which are automatically parsed and used in the execution. 31 | 32 | ### Sample Rate Parameter 33 | To specify the sample rate for the AudioContext, use the following syntax: 34 | 35 | ```js 36 | // @sampleRate = 48000 37 | ``` 38 | 39 | If not specified, the default sample rate of **48000 Hz** is used. This allows easy configuration without manually setting `AudioContextOptions.sampleRate`. 40 | -------------------------------------------------------------------------------- /src/rainfly/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true, 12 | "moduleResolution": "bundler" 13 | } 14 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 15 | // except $lib which is handled by https://kit.svelte.dev/docs/configuration#files 16 | // 17 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 18 | // from the referenced tsconfig.json - TypeScript does not merge them in 19 | } 20 | -------------------------------------------------------------------------------- /src/rainfly/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rainfly", 3 | "version": "1.0.0-beta", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite dev", 7 | "prebuild": "npm i", 8 | "build": "vite build", 9 | "postbuild": "rm -rf ../../_site/rainfly/* && cp -r build/* ../../_site/rainfly/ && rm -rf build/", 10 | "preview": "vite preview", 11 | "check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json", 12 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch", 13 | "lint": "eslint --fix ." 14 | }, 15 | "devDependencies": { 16 | "@sveltejs/kit": "^2.0.0", 17 | "@sveltejs/vite-plugin-svelte": "^3.0.0", 18 | "@types/eslint": "^9.6.0", 19 | "autoprefixer": "^10.4.19", 20 | "eslint": "^8.57.0", 21 | "eslint-config-google": "^0.14.0", 22 | "eslint-plugin-svelte": "^2.36.0", 23 | "globals": "^15.0.0", 24 | "monaco-editor": "^0.50.0", 25 | "postcss": "^8.4.40", 26 | "svelte": "^4.2.7", 27 | "svelte-check": "^3.6.0", 28 | "tailwindcss": "^3.4.7", 29 | "typescript": "^5.0.0", 30 | "vite": "^5.0.3" 31 | }, 32 | "type": "module", 33 | "dependencies": { 34 | "@sveltejs/adapter-static": "^3.0.4", 35 | "jszip": "^3.10.1", 36 | "monaco-vim": "^0.4.1" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/rainfly/postcss.config.js: -------------------------------------------------------------------------------- 1 | // noinspection JSUnusedGlobalSymbols 2 | export default { 3 | plugins: { 4 | tailwindcss: {}, 5 | autoprefixer: {}, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /src/rainfly/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface PageState {} 9 | // interface Platform {} 10 | } 11 | } 12 | 13 | export {}; 14 | -------------------------------------------------------------------------------- /src/rainfly/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/actions/click-outside.js: -------------------------------------------------------------------------------- 1 | export const nodes = new Map(); 2 | 3 | /** 4 | * Listen for clicks outside of the node and call the callback. 5 | * @param {HTMLElement} node - The node to listen for clicks outside of 6 | * @param {Function} callback - callback when click outside occurs 7 | * @return {Object.} Object with destroy method to remove 8 | */ 9 | export const clickOutside = (node, callback) => { 10 | nodes.set(node, callback); 11 | 12 | return {destroy: () => nodes.delete(node)}; 13 | }; 14 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/assets/player-pause.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/assets/player-play.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/assets/player-stop.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/components/Modal.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 | 21 | 24 | 25 | 26 | 36 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/components/Toast.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 17 | 20 | 21 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/components/nav/Nav.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 15 | 16 | rainfly logo 17 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/components/nav/NavDropdownItem.svelte: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/components/nav/NavItem.svelte: -------------------------------------------------------------------------------- 1 | 21 | 22 |
31 | { name } 32 | 38 | 39 | 40 |
41 | 42 | 47 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/components/nav/items/NavHelp.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | showAbout(true)}>About 12 | 13 | 14 | 15 |
16 |
17 |
18 |

Rainfly

19 |

An AudioWorklet DSP Playground for Chromium Web Audio API Project 20 | (2024)

21 |
22 |

Created by @terryzfeng and @kizjkre

23 |
24 | 25 |

See 26 | GitHub 27 | for more information or to submit an issue

28 |
29 |
30 | Rainfly logo 31 |
32 |
33 |
34 | 35 | 36 |

ver {meta.version}

37 |
38 |
39 |
40 | 41 | 46 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/stores/status.js: -------------------------------------------------------------------------------- 1 | import {writable} from 'svelte/store'; 2 | 3 | export const Status = Object.freeze({ 4 | stop: 0, 5 | play: 1, 6 | running: 2, 7 | pause: 3, 8 | }); 9 | 10 | /** 11 | * @type {import('svelte/store').Writable} 12 | */ 13 | export const status = writable(Status.stop); 14 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/stores/vim-status.js: -------------------------------------------------------------------------------- 1 | import {writable} from 'svelte/store'; 2 | 3 | const defaultVim = false; // TODO: load from local storage 4 | 5 | /** 6 | * @type {import('svelte/store').Writable} 7 | */ 8 | export const vimStatus = writable(defaultVim); 9 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/utils/click-outside.js: -------------------------------------------------------------------------------- 1 | import {nodes} from '$lib/actions/click-outside'; 2 | 3 | const clickOutsideListener = (/** @type {Event} */ e) => 4 | [...nodes.entries()].forEach(([node, callback]) => 5 | node !== e.target && callback({ 6 | ...e, 7 | currentTarget: node, 8 | }), 9 | ); 10 | 11 | export default clickOutsideListener; 12 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/utils/file-utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Common utility function for working with files 3 | */ 4 | 5 | import JSZip from 'jszip'; 6 | 7 | /** 8 | * Fetch a file from the given URL and return name and text data 9 | * @param {string} url - URL of the file to fetch 10 | * @return {Promise<{name: string, data: string}>} - Promise that resolves to 11 | * an object with the name and data of the file 12 | */ 13 | export async function fetchTextFile(url) { 14 | let filename = url.split('/').pop(); 15 | if (filename === undefined || filename === '') { 16 | filename = url; 17 | } 18 | 19 | try { 20 | const response = await fetch(url); 21 | if (!response.ok) { 22 | throw new Error(`Failed to fetch ${url}`); 23 | } 24 | const data = await response.text(); 25 | return {name: filename, data}; 26 | } catch (/** @type any */ error) { 27 | return {name: filename, data: 'error: '+ error.message}; 28 | } 29 | } 30 | 31 | /** 32 | * Zip multiple text files into a single blob 33 | * @param {Object.} files - JSON object of 34 | * filenames and data 35 | * @return {Promise} - Promise to blob of zipped files 36 | */ 37 | export async function zipTextFiles(files) { 38 | const zip = new JSZip(); 39 | for (const [filename, data] of Object.entries(files)) { 40 | zip.file(filename, data); 41 | } 42 | return zip.generateAsync({type: 'blob'}); 43 | } 44 | -------------------------------------------------------------------------------- /src/rainfly/src/lib/utils/monaco.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Prepare Monaco Editor API for Vite usage 3 | */ 4 | import * as monaco from 'monaco-editor'; 5 | 6 | import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'; 7 | import tsWorker 8 | from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'; 9 | 10 | self.MonacoEnvironment = { 11 | getWorker: function(_id, label) { 12 | switch (label) { 13 | case 'typescript': 14 | case 'javascript': 15 | // eslint-disable-next-line new-cap 16 | return new tsWorker(); 17 | default: 18 | // eslint-disable-next-line new-cap 19 | return new editorWorker(); 20 | } 21 | }, 22 | }; 23 | 24 | export default monaco; 25 | -------------------------------------------------------------------------------- /src/rainfly/src/routes/+layout.js: -------------------------------------------------------------------------------- 1 | export const prerender = true; 2 | -------------------------------------------------------------------------------- /src/rainfly/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Rainfly 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/rainfly/static/examples/bypass/main.js: -------------------------------------------------------------------------------- 1 | // Use `context` as the AudioContext 2 | // @sampleRate = 48000 3 | 4 | const oscillator = new OscillatorNode(context); 5 | await context.audioWorklet.addModule('processor.js'); 6 | const workletNode = new AudioWorkletNode(context, 'bypass-processor'); 7 | 8 | oscillator.connect(workletNode).connect(context.destination); 9 | oscillator.start(); 10 | -------------------------------------------------------------------------------- /src/rainfly/static/examples/bypass/processor.js: -------------------------------------------------------------------------------- 1 | class BypassProcessor extends AudioWorkletProcessor { 2 | process(inputs, outputs) { 3 | const input = inputs[0]; 4 | const output = outputs[0]; 5 | for (let channel = 0; channel < input.length; ++channel) { 6 | for (let i = 0; i < input[0].length; ++i) { 7 | output[channel][i] = input[channel][i]; 8 | } 9 | } 10 | 11 | return true; 12 | } 13 | } 14 | 15 | registerProcessor('bypass-processor', BypassProcessor); 16 | -------------------------------------------------------------------------------- /src/rainfly/static/examples/examples.json: -------------------------------------------------------------------------------- 1 | { 2 | "examples": [ 3 | { 4 | "name": "Hello Bypass", 5 | "mainCodeUrl": "examples/bypass/main.js", 6 | "processorCodeUrl": "examples/bypass/processor.js" 7 | }, 8 | { 9 | "name": "Hello Sine", 10 | "mainCodeUrl": "examples/sine/main.js", 11 | "processorCodeUrl": "examples/sine/processor.js" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /src/rainfly/static/examples/sine/main.js: -------------------------------------------------------------------------------- 1 | // Use `context` as the AudioContext 2 | // @sampleRate = 48000 3 | 4 | await context.audioWorklet.addModule('processor.js'); 5 | const sineWorkletNode = new AudioWorkletNode(context, 'sine-processor'); 6 | sineWorkletNode.parameters.get('frequency').value = 440; 7 | sineWorkletNode.connect(context.destination); 8 | -------------------------------------------------------------------------------- /src/rainfly/static/examples/sine/processor.js: -------------------------------------------------------------------------------- 1 | class SineProcessor extends AudioWorkletProcessor { 2 | static get parameterDescriptors() { 3 | return [ 4 | { name: 'frequency', defaultValue: 440, }, 5 | ]; 6 | } 7 | 8 | constructor() { 9 | super(); 10 | this.phase = 0; 11 | this.inverseSampleRate = 1 / sampleRate; 12 | } 13 | 14 | process(inputs, outputs, parameters) { 15 | const output = outputs[0]; 16 | const frequency = parameters.frequency[0]; 17 | 18 | for (let i = 0; i < output[0].length; ++i) { 19 | output[0][i] = Math.sin(2 * Math.PI * frequency * this.phase); 20 | this.phase += this.inverseSampleRate; 21 | } 22 | 23 | for (let channel = 1; channel < output.length; ++channel) { 24 | output[channel].set(output[0]); 25 | } 26 | 27 | return true; 28 | } 29 | } 30 | 31 | registerProcessor('sine-processor', SineProcessor); 32 | -------------------------------------------------------------------------------- /src/rainfly/static/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/rainfly/static/processor/recorder-processor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RecorderProcessor records samples on the fly and streams them to the main thread. 3 | */ 4 | class RecorderProcessor extends AudioWorkletProcessor { 5 | process(inputs, outputs) { 6 | const input = inputs[0]; 7 | const output = outputs[0]; 8 | 9 | for (let channel = 0; channel < input.length; channel++) { 10 | output[channel].set(input[channel]); 11 | this.port.postMessage({ channel, data: input[channel] }); 12 | } 13 | 14 | return true; 15 | } 16 | } 17 | 18 | registerProcessor('recorder-processor', RecorderProcessor); -------------------------------------------------------------------------------- /src/rainfly/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-static'; 2 | import {vitePreprocess} from '@sveltejs/vite-plugin-svelte'; 3 | 4 | const BUILD_DIR = '/rainfly'; 5 | 6 | /** @type {import('@sveltejs/kit').Config} */ 7 | const config = { 8 | kit: { 9 | // adapter-auto only supports some environments, see 10 | // https://kit.svelte.dev/docs/adapter-auto for a list. 11 | // If your environment is not supported, or you settled 12 | // on a specific environment, switch out the adapter. See 13 | // https://kit.svelte.dev/docs/adapters for more information 14 | // about adapters. 15 | adapter: adapter(), 16 | appDir: 'app', 17 | paths: { 18 | base: process.argv.includes('dev') ? '' : BUILD_DIR, 19 | }, 20 | }, 21 | preprocess: vitePreprocess(), 22 | }; 23 | 24 | export default config; 25 | -------------------------------------------------------------------------------- /src/rainfly/tailwind.config.js: -------------------------------------------------------------------------------- 1 | // noinspection JSUnusedGlobalSymbols 2 | /** @type {import('tailwindcss').Config} */ 3 | export default { 4 | content: ['./src/**/*.{html,js,svelte,ts}'], 5 | theme: { 6 | extend: { 7 | colors: { 8 | primary: '#94E170', 9 | secondary: '#FFFBD3', 10 | accent: '#FD9494', 11 | }, 12 | fontFamily: { 13 | sans: ['"Outfit"', 'sans-serif'], 14 | mono: ['"Anonymous Pro"', 'monospace'], 15 | }, 16 | gridTemplateRows: { 17 | main: '3rem minmax(0, 4fr) minmax(0, 6fr)', 18 | }, 19 | }, 20 | }, 21 | plugins: [], 22 | }; 23 | -------------------------------------------------------------------------------- /src/rainfly/vite.config.js: -------------------------------------------------------------------------------- 1 | import {sveltekit} from '@sveltejs/kit/vite'; 2 | import {defineConfig} from 'vite'; 3 | import {readFileSync} from 'node:fs'; 4 | 5 | export default defineConfig({ 6 | plugins: [sveltekit()], 7 | // REF: https://stackoverflow.com/a/72141502 8 | define: { 9 | meta: {version: JSON.parse(readFileSync('package.json', 'utf8')).version}, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /src/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | Disallow: /scripts 4 | Sitemap: https://https://googlechromelabs.github.io/web-audio-samples/sitemap.xml -------------------------------------------------------------------------------- /src/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | https://googlechromelabs.github.io/web-audio-samples/ 9 | 2022-04-01T00:00:00+00:00 10 | 1.00 11 | 12 | 13 | https://googlechromelabs.github.io/web-audio-samples/audio-worklet/ 14 | 2021-04-01T00:00:00+00:00 15 | 0.80 16 | 17 | -------------------------------------------------------------------------------- /src/sounds/drum-samples/4OP-FM/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/4OP-FM/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/4OP-FM/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/4OP-FM/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/4OP-FM/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/4OP-FM/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/4OP-FM/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/4OP-FM/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/4OP-FM/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/4OP-FM/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/4OP-FM/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/4OP-FM/tom3.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/CR78/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/CR78/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/CR78/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/CR78/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/CR78/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/CR78/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/CR78/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/CR78/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/CR78/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/CR78/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/CR78/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/CR78/tom3.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/KPR77/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/KPR77/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/KPR77/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/KPR77/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/KPR77/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/KPR77/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/KPR77/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/KPR77/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/KPR77/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/KPR77/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/KPR77/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/KPR77/tom3.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Kit3/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Kit3/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Kit3/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Kit3/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Kit3/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Kit3/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Kit3/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Kit3/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Kit3/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Kit3/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Kit3/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Kit3/tom3.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Kit8/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Kit8/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Kit8/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Kit8/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Kit8/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Kit8/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Kit8/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Kit8/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Kit8/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Kit8/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Kit8/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Kit8/tom3.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/LINN/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/LINN/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/LINN/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/LINN/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/LINN/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/LINN/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/LINN/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/LINN/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/LINN/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/LINN/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/LINN/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/LINN/tom3.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/R8/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/R8/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/R8/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/R8/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/R8/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/R8/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/R8/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/R8/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/R8/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/R8/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/R8/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/R8/tom3.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Stark/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Stark/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Stark/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Stark/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Stark/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Stark/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Stark/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Stark/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Stark/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Stark/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Stark/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Stark/tom3.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Techno/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Techno/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Techno/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Techno/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Techno/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Techno/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Techno/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Techno/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Techno/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Techno/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/Techno/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/Techno/tom3.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/TheCheebacabra1/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/TheCheebacabra1/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/TheCheebacabra1/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/TheCheebacabra1/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/TheCheebacabra1/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/TheCheebacabra1/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/TheCheebacabra1/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/TheCheebacabra1/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/TheCheebacabra1/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/TheCheebacabra1/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/TheCheebacabra1/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/TheCheebacabra1/tom3.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/TheCheebacabra2/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/TheCheebacabra2/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/TheCheebacabra2/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/TheCheebacabra2/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/TheCheebacabra2/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/TheCheebacabra2/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/TheCheebacabra2/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/TheCheebacabra2/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/TheCheebacabra2/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/TheCheebacabra2/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/TheCheebacabra2/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/TheCheebacabra2/tom3.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/acoustic-kit/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/acoustic-kit/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/acoustic-kit/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/acoustic-kit/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/acoustic-kit/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/acoustic-kit/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/acoustic-kit/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/acoustic-kit/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/acoustic-kit/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/acoustic-kit/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/acoustic-kit/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/acoustic-kit/tom3.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat13/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat13/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat13/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat13/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat13/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat13/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat13/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat13/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat13/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat13/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat13/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat13/tom3.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat8/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat8/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat8/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat8/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat8/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat8/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat8/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat8/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat8/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat8/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat8/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat8/tom3.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat9/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat9/hihat.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat9/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat9/kick.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat9/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat9/snare.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat9/tom1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat9/tom1.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat9/tom2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat9/tom2.wav -------------------------------------------------------------------------------- /src/sounds/drum-samples/breakbeat9/tom3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/drum-samples/breakbeat9/tom3.wav -------------------------------------------------------------------------------- /src/sounds/fx/ball-ball-hard2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/ball-ball-hard2.wav -------------------------------------------------------------------------------- /src/sounds/fx/ball-ball-light2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/ball-ball-light2.wav -------------------------------------------------------------------------------- /src/sounds/fx/ball-ball-medium3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/ball-ball-medium3.wav -------------------------------------------------------------------------------- /src/sounds/fx/ball-edge-hard1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/ball-edge-hard1.wav -------------------------------------------------------------------------------- /src/sounds/fx/ball-edge-medium2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/ball-edge-medium2.wav -------------------------------------------------------------------------------- /src/sounds/fx/ball-pocket-balls.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/ball-pocket-balls.wav -------------------------------------------------------------------------------- /src/sounds/fx/cauldron.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/cauldron.wav -------------------------------------------------------------------------------- /src/sounds/fx/filter-noise-2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/filter-noise-2.wav -------------------------------------------------------------------------------- /src/sounds/fx/human-voice.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/human-voice.mp3 -------------------------------------------------------------------------------- /src/sounds/fx/obama-oilspill.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/obama-oilspill.mp3 -------------------------------------------------------------------------------- /src/sounds/fx/penny-spinning.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/penny-spinning.wav -------------------------------------------------------------------------------- /src/sounds/fx/stick-cue-light2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/stick-cue-light2.wav -------------------------------------------------------------------------------- /src/sounds/fx/stick-cue-medium2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/stick-cue-medium2.wav -------------------------------------------------------------------------------- /src/sounds/fx/stick-cue-medium5.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/stick-cue-medium5.wav -------------------------------------------------------------------------------- /src/sounds/fx/ticking.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/ticking.wav -------------------------------------------------------------------------------- /src/sounds/fx/waves.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/waves.wav -------------------------------------------------------------------------------- /src/sounds/fx/white-noise.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/fx/white-noise.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/ambisonic-1o-ir.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/ambisonic-1o-ir.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/backslap1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/backslap1.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/binaural-s3_r4_bd.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/binaural-s3_r4_bd.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/cardiod-35-10-spread.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/cardiod-35-10-spread.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/cardiod-rear-35-10.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/cardiod-rear-35-10.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/cardiod-true-stereo-15-8.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/cardiod-true-stereo-15-8.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/comb-saw1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/comb-saw1.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/comb-saw2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/comb-saw2.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/cosmic-ping-long.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/cosmic-ping-long.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/diffusor3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/diffusor3.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/echo-chamber.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/echo-chamber.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/feedback-spring.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/feedback-spring.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/filter-hipass5000.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/filter-hipass5000.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/filter-lopass160.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/filter-lopass160.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/filter-rhythm3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/filter-rhythm3.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/filter-telephone.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/filter-telephone.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/kitchen-true-stereo.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/kitchen-true-stereo.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/matrix-reverb2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/matrix-reverb2.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/matrix-reverb3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/matrix-reverb3.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/matrix-reverb6.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/matrix-reverb6.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/matrix6-backwards.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/matrix6-backwards.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/noise-spreader1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/noise-spreader1.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/omni-35-10.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/omni-35-10.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/peculiar-backwards.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/peculiar-backwards.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/sifter.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/sifter.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/spatialized1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/spatialized1.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/spatialized2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/spatialized2.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/spatialized3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/spatialized3.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/spatialized4.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/spatialized4.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/spatialized5.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/spatialized5.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/spatialized6.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/spatialized6.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/spatialized7.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/spatialized7.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/spatialized8.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/spatialized8.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/spatialized9.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/spatialized9.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/spreader50-65ms.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/spreader50-65ms.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/super-ceiling-35-10.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/super-ceiling-35-10.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/tim-stretch2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/tim-stretch2.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/tim-warehouse-stretch1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/tim-warehouse-stretch1.wav -------------------------------------------------------------------------------- /src/sounds/impulse-responses/wildecho.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/impulse-responses/wildecho.wav -------------------------------------------------------------------------------- /src/sounds/loops/blueyellow.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/loops/blueyellow.wav -------------------------------------------------------------------------------- /src/sounds/loops/break12.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/loops/break12.wav -------------------------------------------------------------------------------- /src/sounds/loops/break28.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/loops/break28.wav -------------------------------------------------------------------------------- /src/sounds/loops/break29.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/loops/break29.wav -------------------------------------------------------------------------------- /src/sounds/loops/breakbeat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/loops/breakbeat.wav -------------------------------------------------------------------------------- /src/sounds/loops/coolloop7.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/loops/coolloop7.wav -------------------------------------------------------------------------------- /src/sounds/loops/ominous.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/loops/ominous.wav -------------------------------------------------------------------------------- /src/sounds/loops/organ-echo-chords.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/web-audio-samples/8de65f6daa6bea0cdc5583a1833e6da981aa5f73/src/sounds/loops/organ-echo-chords.wav -------------------------------------------------------------------------------- /src/styles/styles.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | 3 | h1 { 4 | @apply text-5xl pb-6; 5 | } 6 | 7 | h2 { 8 | @apply text-2xl pb-2; 9 | } 10 | 11 | a, a:active, a:visited { 12 | @apply text-blue-600; 13 | } 14 | 15 | a:hover { 16 | @apply text-blue-400 underline; 17 | } 18 | 19 | p { 20 | @apply mb-3; 21 | } 22 | 23 | button { 24 | @apply text-lg text-white bg-blue-600 rounded-md px-3 py-1; 25 | } 26 | 27 | button[disabled] { 28 | @apply cursor-not-allowed opacity-50; 29 | } 30 | 31 | .inactive { 32 | @apply fill-blue-400; 33 | } 34 | 35 | .active { 36 | @apply fill-white; 37 | } 38 | 39 | @tailwind utilities; 40 | 41 | .footer { 42 | @apply text-sm; 43 | } 44 | 45 | .demo-box { 46 | @apply border border-gray-400 rounded-md p-3 my-6; 47 | } 48 | -------------------------------------------------------------------------------- /src/tests/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: tests 4 | title: Various tests for Web Audio API 5 | parent: landing 6 | to_root_dir: ../ 7 | --- 8 | 9 | {% extends "../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |
14 |

Tests

15 |

TODO: Various tests for Chrome Web Audio API

16 |

Under Progress...

17 |
18 | 19 | {% for section in tests_data %} 20 |
21 |

22 | {{ section.title }} 23 |

24 |
25 | {% for entry in section.entries %} 26 |
27 | 28 | {{ entry.title }} 29 | 30 |

{{ entry.description }}

31 |
32 | {% endfor %} 33 |
34 |
35 | {% endfor %} 36 | 37 | {% endblock %} -------------------------------------------------------------------------------- /src/tests/pannernode/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: test-pannernode 4 | title: Glitches in PannerNode 5 | parent: tests 6 | to_root_dir: ../../ 7 | --- 8 | 9 | {% extends "../../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |

{{ eleventyNavigation.title }}

14 |

Press "Start Audio" button to start the test. The test will play 3 segments 15 | (3 seconds each) of the ConstantSourceNode with a DC offset of 0.5. This 16 | source is spatialized by the PannerNode with HRTF. Ideally, the spatialization 17 | should not cause any artifacts. (e.g. glitches, sudden changes)

18 | 26 |

Refresh the page to run the test again.

27 | 28 |
29 | 30 | {% include "../../_includes/example-source-code.njk" %} 31 |
32 | 33 |
35 |
36 |
37 |
38 | 39 | 40 | 41 | {% endblock %} 42 | -------------------------------------------------------------------------------- /src/tests/playwright/pages/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Web Audio Test Suite 9 | 10 | 11 |
12 |

Web Audio Test Suite

13 |

0/0

14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
Test NameResultTimeOutputRun
28 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/tests/playwright/pages/live-suite/scripts/console-override.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Overrides console methods to capture outputs in `output` array 3 | * for debugging/tests. Handles common methods like log, error, info, and more, 4 | * storing { method, arguments }. 5 | */ 6 | export const output = []; 7 | 8 | [ 9 | 'log', 'debug', 'info', 'error', 'warning', 'dir', 'dirxml', 10 | 'table', 'trace', 'clear', 'group', 'groupCollapsed', 'groupEnd', 11 | 'assert', 'profile', 'profileEnd', 'count', 'timeEnd', 12 | ].forEach((method) => { 13 | const original = console[method]; 14 | console[method] = (...args) => { 15 | (method !== 'assert' || (method === 'assert' && !args[0])) && 16 | output.push({method, args}); 17 | return original.apply(console, args); 18 | }; 19 | }); 20 | -------------------------------------------------------------------------------- /src/tests/playwright/pages/live-suite/scripts/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Initializes the Web Audio Test Suite by converting specified 3 | * HTML test files to interactive DOM elements. 4 | */ 5 | import {convertTestFiles} from './test-file-converter.js'; 6 | 7 | // Flag for live test suite environment 8 | window._isTestSuiteMode = true; 9 | 10 | const testEnded = () => 11 | new Promise((resolve) => window._webAudioTestEnded = resolve); 12 | document.querySelector('#run-all').addEventListener('click', async () => { 13 | const buttons = document.querySelectorAll('button[data-type=test]'); 14 | for (const button of buttons) { 15 | button.click(); 16 | await testEnded(); 17 | } 18 | }); 19 | 20 | (async () => { 21 | const tests = await (await fetch('tests.json')).json(); 22 | 23 | document.querySelector('#total').innerText = 24 | Object.values(tests).reduce((sum, group) => sum + group.length, 0); 25 | 26 | convertTestFiles([ 27 | ...tests.benchmark.map((test) => test.path), 28 | ...tests.performance.map((test) => test.path), 29 | ]); 30 | })(); 31 | -------------------------------------------------------------------------------- /src/tests/playwright/pages/perf-gain-node.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 34 | Gain Performance Test 35 | 36 | 37 |

Gain Performance Test

38 |

Test performance of ConstantSourceNode => 100 Gain Nodes; Port of 39 | 40 | Blink WPT Performance Gain Test 41 |

42 | 43 | 44 | -------------------------------------------------------------------------------- /src/tests/playwright/pages/realtime-sine.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 30 | Realtime Sine Oscillator Test 31 | 32 | 33 |

Realtime Sine Oscillator Test

34 |

Play a sine wave at 440Hz for 1 second at 48kHz sample rate.

35 | 36 | 37 | -------------------------------------------------------------------------------- /src/tests/playwright/pages/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | My Web Audio Test 20 | 21 | 22 |

My Web Audio Test

23 |

My web audio test description.

24 | 25 | -------------------------------------------------------------------------------- /src/tests/playwright/pages/tests.json: -------------------------------------------------------------------------------- 1 | { 2 | "benchmark": [ 3 | { 4 | "name": "Hello Sine (realtime)", 5 | "path": "pages/realtime-sine.html" 6 | }, 7 | { 8 | "name": "Hello Sine (realtime) (WebChucK)", 9 | "path": "pages/chuck-realtime-sine.html", 10 | "playwright-ignore": true 11 | } 12 | ], 13 | "performance": [ 14 | { 15 | "name": "Gain Test", 16 | "path": "pages/perf-gain-node.html" 17 | }, 18 | { 19 | "name": "Panner Test", 20 | "path": "pages/perf-panner-node.html" 21 | }, 22 | { 23 | "name": "Timeline Insert Event Test", 24 | "path": "pages/perf-timeline-insert-event.html" 25 | }, 26 | { 27 | "name": "Audio Buffer Source Test", 28 | "path": "pages/perf-audio-buffer-source-node.html" 29 | }, 30 | { 31 | "name": "Audio Worklet Node Test", 32 | "path": "pages/perf-audio-worklet-node.html" 33 | }, 34 | { 35 | "name": "Biquad Filter Node Test", 36 | "path": "pages/perf-biquad-filter-node.html" 37 | }, 38 | { 39 | "name": "Dynamics Compressor Node (Knee) Test", 40 | "path": "pages/perf-dynamics-compressor-node-knee.html" 41 | }, 42 | { 43 | "name": "Dynamics Compressor Node (Post-Knee) Test", 44 | "path": "pages/perf-dynamics-compressor-node-post-knee.html" 45 | }, 46 | { 47 | "name": "Dynamics Compressor Node (Pre-Knee) Test", 48 | "path": "pages/perf-dynamics-compressor-node-pre-knee.html" 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /src/tests/playwright/pages/util/bypass-processor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class BypassProcessor 3 | * @extends AudioWorkletProcessor 4 | */ 5 | class BypassProcessor extends AudioWorkletProcessor { 6 | process(inputs, outputs) { 7 | const input = inputs[0]; 8 | const output = outputs[0]; 9 | for (let channel = 0; channel < input.length; ++channel) { 10 | output[channel].set(input[channel]); 11 | } 12 | 13 | return true; 14 | } 15 | } 16 | 17 | registerProcessor('bypass-processor', BypassProcessor); 18 | -------------------------------------------------------------------------------- /src/tests/playwright/pages/util/recorder/recorder-processor.js: -------------------------------------------------------------------------------- 1 | const MAX_RENDER_QUANTUM = 128; 2 | 3 | /** 4 | * @classdesc The AudioWorklet RecorderProcessor records raw PCM samples 5 | * from node input into a fixed-length recording buffer. Data is posted once 6 | * the buffer is filled. Will also pass through audio from input to output. 7 | */ 8 | class RecorderProcessor extends AudioWorkletProcessor { 9 | constructor(options) { 10 | super(); 11 | this._position = 0; 12 | this._numberOfSamples = options.processorOptions.numberOfSamples; 13 | this._numberOfChannels = options.processorOptions.numberOfChannels; 14 | this._channelData = new Array(this._numberOfChannels) 15 | .fill(new Float32Array(this._numberOfSamples)); 16 | } 17 | 18 | process(inputs, outputs) { 19 | const input = inputs[0]; 20 | const output = outputs[0]; 21 | 22 | const samplesToRecord = Math.min(MAX_RENDER_QUANTUM, 23 | this._numberOfSamples - this._position); 24 | 25 | for (let channel = 0; channel < input.length; ++channel) { 26 | output[channel].set(input[channel]); // pass-through 27 | this._channelData[channel] 28 | .set(input[channel].subarray(0, samplesToRecord), this._position); 29 | } 30 | 31 | this._position += samplesToRecord; 32 | if (this._position === this._numberOfSamples) { 33 | this.port.postMessage({ 34 | message: 'RECORD_DONE', 35 | channelData: this._channelData, 36 | }); 37 | return false; 38 | } 39 | 40 | return true; 41 | } 42 | } 43 | 44 | registerProcessor('test-recorder', RecorderProcessor); 45 | -------------------------------------------------------------------------------- /src/tests/playwright/runner.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Web Audio Test Suite using the Playwright Framework. 3 | * Read `pages/tests.json` for all tests for Playwright to build. Playwright 4 | * will navigate and run each HTML page, capture logs, and finally check if the 5 | * `evaluate` function which sets `webAudioEvaluate` returns true. 6 | */ 7 | import {test, expect} from '@playwright/test'; 8 | import tests from './pages/tests.json'; 9 | 10 | // Capture test console logs 11 | test.beforeEach(async ({page}) => 12 | page.on('console', (msg) => 13 | console[msg.type() === 'assert' ? 'error' : msg.type()](msg.text()), 14 | ), 15 | ); 16 | 17 | // Check if test passed 18 | test.afterEach(async ({page}) => { 19 | // @ts-ignore 20 | // eslint-disable-next-line no-undef 21 | // noinspection TypeScriptUnresolvedReference 22 | const result = await page.evaluate(async () => await webAudioEvaluate); 23 | expect(result).toBeTruthy(); 24 | }); 25 | 26 | test.describe('Benchmark Tests', () => { 27 | tests.benchmark 28 | .filter((test) => !test['playwright-ignore']) 29 | .forEach(({name, path}) => { 30 | test(name, async ({page}) => { 31 | await page.goto(path); 32 | }); 33 | }); 34 | }); 35 | 36 | test.describe('Performance Tests', () => { 37 | tests.performance 38 | .filter((test) => !test['playwright-ignore']) 39 | .forEach(({name, path}) => { 40 | test(name, async ({page}) => { 41 | await page.goto(path); 42 | }); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /src/tests/playwright/version.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Playwright auxiliary test for checking browser version 3 | */ 4 | import {test, expect} from '@playwright/test'; 5 | 6 | test('Browser version', async ({browser}) => { 7 | test.info().annotations.push({ 8 | type: 'browser version', 9 | description: browser.version(), 10 | }); 11 | 12 | const version = await browser.version(); 13 | console.log('Browser version:', version); 14 | expect(version).not.toBe(null); 15 | }); 16 | -------------------------------------------------------------------------------- /src/tests/resampler/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: test-resampler-bug 4 | title: Resampler Verificaiton 5 | parent: tests 6 | to_root_dir: ../../ 7 | --- 8 | 9 | {% extends "../../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |

{{ eleventyNavigation.title }}

14 |

Press "Start Audio" button to start the test. Check if you can hear any 15 | audio glitches from your eadbuds or a headset. See 16 | Issue 331682035 for more details. 17 |

18 |

Refresh the page to run the test again.

19 | 20 |
21 | 22 | {% include "../../_includes/example-source-code.njk" %} 23 |
24 | 25 |
27 |
28 |
29 |
30 | 31 | 32 | 33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /src/tests/setsinkid/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | eleventyNavigation: 3 | key: test-setsinkid 4 | title: Manual test for AudioContext.setSinkId() 5 | parent: tests 6 | to_root_dir: ../../ 7 | --- 8 | 9 | {% extends "../../_includes/base.njk" %} 10 | 11 | {% block content %} 12 | 13 |

AudioContext.setSinkId(): Manual Test

14 |

NOTE: This test requires a permission for microphone to access the available 15 | audio devices in the system.

16 | 17 |
18 |
19 | 20 | 24 |
25 | 26 |
27 | 28 |
30 |
31 |
32 |
33 | 34 | 35 | 36 | {% endblock %} -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: [ 3 | './src/**/*.html', 4 | './src/**/*.njk', 5 | ], 6 | }; 7 | --------------------------------------------------------------------------------