├── .eslintrc.json
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── app.yaml
├── assets
├── .gitkeep
├── audio
│ └── drums
│ │ ├── 36.mp3
│ │ ├── 38.mp3
│ │ ├── 42.mp3
│ │ ├── 45.mp3
│ │ ├── 46.mp3
│ │ ├── 48.mp3
│ │ ├── 49.mp3
│ │ ├── 50.mp3
│ │ └── 51.mp3
├── drums_small
│ ├── decoder_multi_rnn_cell_cell_0_lstm_cell_bias
│ ├── decoder_multi_rnn_cell_cell_0_lstm_cell_kernel
│ ├── decoder_multi_rnn_cell_cell_1_lstm_cell_bias
│ ├── decoder_multi_rnn_cell_cell_1_lstm_cell_kernel
│ ├── decoder_output_projection_bias
│ ├── decoder_output_projection_kernel
│ ├── decoder_z_to_initial_state_bias
│ ├── decoder_z_to_initial_state_kernel
│ ├── encoder_cell_0_bidirectional_rnn_bw_multi_rnn_cell_cell_0_lstm_cell_bias
│ ├── encoder_cell_0_bidirectional_rnn_bw_multi_rnn_cell_cell_0_lstm_cell_kernel
│ ├── encoder_cell_0_bidirectional_rnn_fw_multi_rnn_cell_cell_0_lstm_cell_bias
│ ├── encoder_cell_0_bidirectional_rnn_fw_multi_rnn_cell_cell_0_lstm_cell_kernel
│ ├── encoder_mu_bias
│ ├── encoder_mu_kernel
│ └── manifest.json
├── fonts
│ └── FoundersGrotesk-Regular.otf
└── images
│ ├── ai-experiment.svg
│ ├── beat-blender-social.jpeg
│ ├── beat-blender-social.png
│ ├── blend-palindrome-2.gif
│ ├── edit.png
│ ├── exit.svg
│ ├── favicon-small.png
│ ├── favicon.png
│ ├── friends-at-google.svg
│ ├── magenta-logo.png
│ ├── pause-button.svg
│ ├── play-button.svg
│ ├── screenshot.jpg
│ └── tempo.svg
├── index.html
├── js
├── canvas-utils.js
├── commands
│ ├── on-draw-path.js
│ ├── on-draw-release.js
│ ├── on-puck-drag.js
│ └── undo-manager.js
├── debug-mode.js
├── firebase.js
├── get-mouse-position.js
├── hub.js
├── index.js
├── midi-out.js
├── models
│ ├── color.js
│ ├── modals.js
│ ├── play-modes.js
│ └── responsive.js
├── samples.js
├── utils.js
└── views
│ ├── base-view.js
│ ├── button.js
│ ├── debug-layout-grid.js
│ ├── grid.js
│ ├── layout-containers.js
│ ├── modal.js
│ ├── preset-button-group.js
│ ├── select-midi-out.js
│ ├── sequence-player.js
│ ├── sequencer-grid.js
│ ├── sequencer-label.js
│ ├── spinner.js
│ └── tiles.js
├── json
├── preset-beats.json
├── response.json
├── response2.json
├── response3.json
└── response4.json
├── less
├── _mixins.less
├── base-button.less
├── base-select.less
├── bpm.less
├── edit-sequencer-button.less
├── grid-view.less
├── layout.less
├── midi-out.less
├── modal.less
├── play-pause-button.less
├── preset-buttons.less
├── responsive.less
├── spinner.less
├── splash.less
├── style.less
├── tile.less
└── toggle.less
├── main.py
├── package.json
└── yarn.lock
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "commonjs": true,
5 | "es6": true
6 | },
7 | "extends": "eslint:recommended",
8 | "parserOptions": {
9 | "sourceType": "module",
10 | "ecmaVersion": 2017
11 | },
12 | "rules": {
13 | "no-extra-boolean-cast": 0,
14 | "no-console": 0,
15 | "indent": [
16 | "error",
17 | 4
18 | ],
19 | "linebreak-style": [
20 | "error",
21 | "unix"
22 | ],
23 | "quotes": [
24 | "error",
25 | "single"
26 | ],
27 | "semi": [
28 | "error",
29 | "always"
30 | ]
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | npm-debug.log
2 | yarn-error.log
3 | .idea
4 | *.pyc
5 | assets/*.js
6 | assets/*.css
7 | node_modules/
8 | .sass-cache
9 | .DS_Store
10 | *.swp
11 | public/*
12 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement. You (or your employer) retain the copyright to your contribution,
10 | this simply gives us permission to use and redistribute your contributions as
11 | part of the project. Head over to to see
12 | your current agreements on file or to sign a new one.
13 |
14 | You generally only need to submit a CLA once, so if you've already submitted one
15 | (even if it was for a different project), you probably don't need to do it
16 | again.
17 |
18 | ## Code reviews
19 |
20 | All submissions, including submissions by project members, require review. We
21 | use GitHub pull requests for this purpose. Consult
22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
23 | information on using pull requests.
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Beat Blender
2 | ### Blend beats using machine learning to create music in a fun new way. [g.co/beatblender](https://g.co/beatblender)
3 |
4 | Built using [deeplearn.js](https://deeplearnjs.org) and [MusicVAE](https://github.com/tensorflow/magenta/tree/master/magenta/models/music_vae).
5 |
6 | 
7 |
8 |
9 |
10 | ## Usage
11 |
12 | Beat Blender requires the [GCloud SDK](https://cloud.google.com/sdk/downloads) for running the server and [node + npm](http://nodejs.org) for javascript development.
13 |
14 |
15 | 1. Run `npm install` to install all of the dependencies of this project.
16 | 2. Run `npm start` to begin all file-watchers and to initialize the server on port `8080`
17 | 3. Open `http://localhost:8080`
18 |
19 |
20 | ## Easter eggs
21 | You have added a few query-strings that you can play with, you can load a different model for MusicVAE using `checkpoint=url` or a custom model for generating new beats with `samplerCheckpoint=url`
22 |
23 |
24 | ## Contributors
25 | Made by [Kyle Phillips](http://haptic-data.com) and [Torin Blankensmith](http://torinblankensmith.com) with friends at the Google Creative Lab in collaboration with [Adam Roberts](https://github.com/adarob) and the Magenta team.
26 |
27 |
28 | This is not an officially supported Google product.
29 |
30 | ## License
31 | Copyright 2017 Google Inc.
32 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
33 | http://www.apache.org/licenses/LICENSE-2.0
34 |
35 |
36 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
37 |
38 | ## Final Thoughts
39 | We encourage open sourcing projects as a way of learning from each other. Please respect our and other creators’ rights, including copyright and trademark rights when present, when sharing these works and creating derivative work.
40 |
41 | If you want more info on Google's policy, you can find that [here](https://www.google.com/policies/).
42 |
--------------------------------------------------------------------------------
/app.yaml:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Google Inc.
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 | runtime: python27
16 | api_version: 1
17 | threadsafe: true
18 |
19 | handlers:
20 |
21 | - url: /
22 | script: main.app
23 |
24 | - url: /ai/beat-blender/view
25 | script: main.app
26 |
27 | - url: /ai/beat-blender/view/
28 | static_files: index.html
29 | upload: index.html
30 |
31 | - url: /ai/beat-blender/view/main
32 | static_files: index.html
33 | upload: index.html
34 |
35 | - url: /ai/beat-blenader/view/share
36 | static_files: index.html
37 | upload: index.html
38 |
39 | - url: /ai/beat-blenader/view/share/
40 | static_files: index.html
41 | upload: index.html
42 |
43 | - url: /ai/beat-blender/view/share/.*
44 | static_files: index.html
45 | upload: index.html
46 |
47 | - url: /ai/beat-blender/view/about
48 | static_files: index.html
49 | upload: index.html
50 |
51 | - url: /ai/beat-bleander/view/main
52 | static_files: index.html
53 | upload: index.html
54 |
55 | - url: /ai/beat-blender/view/assets
56 | static_dir: assets
57 |
58 | - url: /ai/beat-blender/view/third_party
59 | static_dir: third_party
60 |
61 | skip_files:
62 | - ^.git/.*
63 | - ^.*node_modules(/.*)?
64 | - ^node_modules/(.*/)?
65 | - ^js/(.*/)?
66 | - ^json/(.*/)?
67 | - ^less/(.*/)?
68 | - ^assets/big_melodies/(.*/)?
69 | - ^big_loopz_mel/(.*/)?
70 | - ^ml-loopz-demo-website/(.*/)?
71 | - ^big_loopz_mel/(.*/)?
72 | - ^assets/big_melodies/(.*/)?
73 |
--------------------------------------------------------------------------------
/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/.gitkeep
--------------------------------------------------------------------------------
/assets/audio/drums/36.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/audio/drums/36.mp3
--------------------------------------------------------------------------------
/assets/audio/drums/38.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/audio/drums/38.mp3
--------------------------------------------------------------------------------
/assets/audio/drums/42.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/audio/drums/42.mp3
--------------------------------------------------------------------------------
/assets/audio/drums/45.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/audio/drums/45.mp3
--------------------------------------------------------------------------------
/assets/audio/drums/46.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/audio/drums/46.mp3
--------------------------------------------------------------------------------
/assets/audio/drums/48.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/audio/drums/48.mp3
--------------------------------------------------------------------------------
/assets/audio/drums/49.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/audio/drums/49.mp3
--------------------------------------------------------------------------------
/assets/audio/drums/50.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/audio/drums/50.mp3
--------------------------------------------------------------------------------
/assets/audio/drums/51.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/audio/drums/51.mp3
--------------------------------------------------------------------------------
/assets/drums_small/decoder_multi_rnn_cell_cell_0_lstm_cell_bias:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/drums_small/decoder_multi_rnn_cell_cell_0_lstm_cell_bias
--------------------------------------------------------------------------------
/assets/drums_small/decoder_multi_rnn_cell_cell_0_lstm_cell_kernel:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/drums_small/decoder_multi_rnn_cell_cell_0_lstm_cell_kernel
--------------------------------------------------------------------------------
/assets/drums_small/decoder_multi_rnn_cell_cell_1_lstm_cell_bias:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/drums_small/decoder_multi_rnn_cell_cell_1_lstm_cell_bias
--------------------------------------------------------------------------------
/assets/drums_small/decoder_multi_rnn_cell_cell_1_lstm_cell_kernel:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/drums_small/decoder_multi_rnn_cell_cell_1_lstm_cell_kernel
--------------------------------------------------------------------------------
/assets/drums_small/decoder_output_projection_bias:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/drums_small/decoder_output_projection_bias
--------------------------------------------------------------------------------
/assets/drums_small/decoder_output_projection_kernel:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/drums_small/decoder_output_projection_kernel
--------------------------------------------------------------------------------
/assets/drums_small/decoder_z_to_initial_state_bias:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/drums_small/decoder_z_to_initial_state_bias
--------------------------------------------------------------------------------
/assets/drums_small/decoder_z_to_initial_state_kernel:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/drums_small/decoder_z_to_initial_state_kernel
--------------------------------------------------------------------------------
/assets/drums_small/encoder_cell_0_bidirectional_rnn_bw_multi_rnn_cell_cell_0_lstm_cell_bias:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/drums_small/encoder_cell_0_bidirectional_rnn_bw_multi_rnn_cell_cell_0_lstm_cell_bias
--------------------------------------------------------------------------------
/assets/drums_small/encoder_cell_0_bidirectional_rnn_bw_multi_rnn_cell_cell_0_lstm_cell_kernel:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/drums_small/encoder_cell_0_bidirectional_rnn_bw_multi_rnn_cell_cell_0_lstm_cell_kernel
--------------------------------------------------------------------------------
/assets/drums_small/encoder_cell_0_bidirectional_rnn_fw_multi_rnn_cell_cell_0_lstm_cell_bias:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/drums_small/encoder_cell_0_bidirectional_rnn_fw_multi_rnn_cell_cell_0_lstm_cell_bias
--------------------------------------------------------------------------------
/assets/drums_small/encoder_cell_0_bidirectional_rnn_fw_multi_rnn_cell_cell_0_lstm_cell_kernel:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/drums_small/encoder_cell_0_bidirectional_rnn_fw_multi_rnn_cell_cell_0_lstm_cell_kernel
--------------------------------------------------------------------------------
/assets/drums_small/encoder_mu_bias:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/drums_small/encoder_mu_bias
--------------------------------------------------------------------------------
/assets/drums_small/encoder_mu_kernel:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/drums_small/encoder_mu_kernel
--------------------------------------------------------------------------------
/assets/drums_small/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "decoder/multi_rnn_cell/cell_0/lstm_cell/bias": {
3 | "filename": "decoder_multi_rnn_cell_cell_0_lstm_cell_bias",
4 | "shape": [
5 | 1024
6 | ]
7 | },
8 | "decoder/multi_rnn_cell/cell_0/lstm_cell/kernel": {
9 | "filename": "decoder_multi_rnn_cell_cell_0_lstm_cell_kernel",
10 | "shape": [
11 | 1024,
12 | 1024
13 | ]
14 | },
15 | "decoder/multi_rnn_cell/cell_1/lstm_cell/bias": {
16 | "filename": "decoder_multi_rnn_cell_cell_1_lstm_cell_bias",
17 | "shape": [
18 | 1024
19 | ]
20 | },
21 | "decoder/multi_rnn_cell/cell_1/lstm_cell/kernel": {
22 | "filename": "decoder_multi_rnn_cell_cell_1_lstm_cell_kernel",
23 | "shape": [
24 | 512,
25 | 1024
26 | ]
27 | },
28 | "decoder/output_projection/bias": {
29 | "filename": "decoder_output_projection_bias",
30 | "shape": [
31 | 512
32 | ]
33 | },
34 | "decoder/output_projection/kernel": {
35 | "filename": "decoder_output_projection_kernel",
36 | "shape": [
37 | 256,
38 | 512
39 | ]
40 | },
41 | "decoder/z_to_initial_state/bias": {
42 | "filename": "decoder_z_to_initial_state_bias",
43 | "shape": [
44 | 1024
45 | ]
46 | },
47 | "decoder/z_to_initial_state/kernel": {
48 | "filename": "decoder_z_to_initial_state_kernel",
49 | "shape": [
50 | 256,
51 | 1024
52 | ]
53 | },
54 | "encoder/cell_0/bidirectional_rnn/bw/multi_rnn_cell/cell_0/lstm_cell/bias": {
55 | "filename": "encoder_cell_0_bidirectional_rnn_bw_multi_rnn_cell_cell_0_lstm_cell_bias",
56 | "shape": [
57 | 2048
58 | ]
59 | },
60 | "encoder/cell_0/bidirectional_rnn/bw/multi_rnn_cell/cell_0/lstm_cell/kernel": {
61 | "filename": "encoder_cell_0_bidirectional_rnn_bw_multi_rnn_cell_cell_0_lstm_cell_kernel",
62 | "shape": [
63 | 522,
64 | 2048
65 | ]
66 | },
67 | "encoder/cell_0/bidirectional_rnn/fw/multi_rnn_cell/cell_0/lstm_cell/bias": {
68 | "filename": "encoder_cell_0_bidirectional_rnn_fw_multi_rnn_cell_cell_0_lstm_cell_bias",
69 | "shape": [
70 | 2048
71 | ]
72 | },
73 | "encoder/cell_0/bidirectional_rnn/fw/multi_rnn_cell/cell_0/lstm_cell/kernel": {
74 | "filename": "encoder_cell_0_bidirectional_rnn_fw_multi_rnn_cell_cell_0_lstm_cell_kernel",
75 | "shape": [
76 | 522,
77 | 2048
78 | ]
79 | },
80 | "encoder/mu/bias": {
81 | "filename": "encoder_mu_bias",
82 | "shape": [
83 | 256
84 | ]
85 | },
86 | "encoder/mu/kernel": {
87 | "filename": "encoder_mu_kernel",
88 | "shape": [
89 | 1024,
90 | 256
91 | ]
92 | }
93 | }
--------------------------------------------------------------------------------
/assets/fonts/FoundersGrotesk-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/fonts/FoundersGrotesk-Regular.otf
--------------------------------------------------------------------------------
/assets/images/ai-experiment.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
10 |
12 |
13 |
15 |
17 |
19 |
22 |
25 |
27 |
29 |
32 |
35 |
37 |
39 |
41 |
43 |
45 |
48 |
50 |
53 |
56 |
58 |
59 |
--------------------------------------------------------------------------------
/assets/images/beat-blender-social.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/images/beat-blender-social.jpeg
--------------------------------------------------------------------------------
/assets/images/beat-blender-social.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/images/beat-blender-social.png
--------------------------------------------------------------------------------
/assets/images/blend-palindrome-2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/images/blend-palindrome-2.gif
--------------------------------------------------------------------------------
/assets/images/edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/images/edit.png
--------------------------------------------------------------------------------
/assets/images/exit.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Close
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/assets/images/favicon-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/images/favicon-small.png
--------------------------------------------------------------------------------
/assets/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/images/favicon.png
--------------------------------------------------------------------------------
/assets/images/friends-at-google.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
10 |
13 |
16 |
19 |
21 |
23 |
25 |
27 |
30 |
33 |
36 |
39 |
41 |
43 |
45 |
48 |
50 |
53 |
56 |
58 |
60 |
63 |
66 |
69 |
72 |
76 |
77 |
80 |
83 |
84 |
--------------------------------------------------------------------------------
/assets/images/magenta-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/images/magenta-logo.png
--------------------------------------------------------------------------------
/assets/images/pause-button.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Shape
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/assets/images/play-button.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Shape
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/assets/images/screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlecreativelab/beat-blender/af42ce5ce4fdcfc981b3dc7f84cc70ee7d9302b3/assets/images/screenshot.jpg
--------------------------------------------------------------------------------
/assets/images/tempo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | tempo
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Beat Blender
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
Beat Blender
33 |
34 |
Blend beats using machine learning to create music in a fun new way.
35 |
LOADING...
36 |
Built with Deeplearn.js
37 | Learn how it works
38 |
39 |
40 |
Sorry, looks like your browser or device doesn't support this experiment.
41 | Learn more about Beat Blender here . Or try visiting this site in a browser like Chrome.
42 |
43 |
44 |
58 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
PRESET BEATS
80 |
81 |
EDIT CORNERS
82 |
83 |
84 |
85 |
102 |
103 |
104 |
105 |
106 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/js/canvas-utils.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import * as grid2d from 'grid2d';
16 | import { toCSSString } from './models/color';
17 |
18 |
19 | /**
20 | * this module is for functions that assist in rendering common application
21 | * data to a canvas, for example a grid
22 | */
23 |
24 |
25 | export const dpr = ()=> 2; //window.devicePixelRatio || 1;
26 |
27 |
28 | export const setCanvasSize = (canvas, width, height)=>{
29 | canvas.width = width * dpr();
30 | canvas.height = height * dpr();
31 | // scaling to dpr should be covered in css, not in this function
32 | // Object.assign(canvas.style, {
33 | // width: (canvas.width / dpr()) + 'px',
34 | // height: (canvas.height / dpr()) + 'px'
35 | // });
36 | return canvas;
37 | };
38 |
39 |
40 |
41 | export const renderToNewCanvas = ({ width, height }, fn)=>{
42 | const el = document.createElement('canvas');
43 | el.width = width;
44 | el.height = height;
45 | const ctx = el.getContext('2d');
46 | fn(ctx);
47 | return el;
48 | };
49 |
50 |
51 | export const renderGridStrokes = (ctx, grid, color, lineWidth=2, widthScale=1, heightScale=1)=>{
52 | ctx.strokeStyle = toCSSString(color);
53 | ctx.lineWidth = lineWidth * dpr();
54 | ctx.beginPath();
55 | const h = 2;
56 | for(let col=0; coltrue), rounding=Math.ceil)=>{
84 |
85 | const cw = rounding(grid2d.cellWidth(grid) * dpr() * widthScale);
86 | const ch = rounding(grid2d.cellHeight(grid) * dpr() * heightScale);
87 |
88 |
89 | for(let x=0; x{
109 | ctx.strokeStyle = 'white';
110 | ctx.lineWidth = 10 * dpr();
111 | ctx.beginPath();
112 | for(let i=0; i{
120 | ctx.fillStyle = color;
121 | for(let i=0; i 0.01){
29 | path.push(pt);
30 | }
31 |
32 | set({
33 | pathLerp: 0,
34 | path
35 | });
36 | }
37 |
--------------------------------------------------------------------------------
/js/commands/on-draw-release.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import { lerpPath, pathLength, times } from '../utils';
17 | import * as grid2d from 'grid2d';
18 |
19 | export default function({ state, set }){
20 | if(!state.path.length){
21 | return;
22 | }
23 |
24 | const n = pathLength(state.path) * 30;
25 | const equids = times(n, (i, n)=> lerpPath(state.path, i/(n-1)));
26 |
27 |
28 | const cells = [];
29 |
30 | const points = [];
31 | let lastCell = {};
32 | for(let i=0; i this.max && safety < 1000){
81 | this.removeOldest(index);
82 | safety++;
83 | }
84 | this.app.setDeep(`${this.key}.${index}`, hist);
85 | }
86 |
87 | /**
88 | * remove the newest item from history
89 | * @param {number} index for history
90 | * @returns {any} newest item
91 | */
92 | popHistory(index){
93 | assert(this.size(index) > 0, 'history is empty');
94 | const hist = this.get(index);
95 | const last = hist.shift();
96 | this.app.setDeep(`${this.key}.${index}`, hist);
97 | return last;
98 | }
99 |
100 | removeOldest(index){
101 | assert(this.size(index) > 0, 'history is empty');
102 | const hist = this.get(index);
103 | const oldest = hist.pop();
104 | this.app.setDeep(`${this.key}.${index}`, hist);
105 | return oldest;
106 | }
107 |
108 | size(index){
109 | return this.app.state[this.key][index].length;
110 | }
111 | }
112 |
113 |
--------------------------------------------------------------------------------
/js/debug-mode.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import { save, get } from './firebase';
16 | import DAT from 'dat-gui';
17 |
18 |
19 | let _initialized = false;
20 |
21 |
22 | export const isInitialized = ()=>_initialized;
23 |
24 |
25 | export const initialize = function(state, page){
26 | if(_initialized){
27 | return;
28 | }
29 | _initialized = true;
30 | const gui = new DAT.GUI();
31 |
32 | get().then(snapshot=>{
33 |
34 | const shareState = {
35 | save: ()=> save(state).then((snapshot)=> console.log(snapshot)),
36 | selected: null
37 | };
38 |
39 | const shares = snapshot.val();
40 |
41 | gui.add(shareState, 'selected', Object.keys(shares)).onChange(key=>{
42 | page(`/share/${key}`);
43 | });
44 |
45 | gui.add(shareState, 'save');
46 | });
47 | };
48 |
--------------------------------------------------------------------------------
/js/firebase.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | /*global: firebase */
16 | import { generate as uuid } from 'shortid';
17 | const { firebase } = window;
18 |
19 | // Initialize Firebase
20 | const config = {
21 | //put your firebase config here
22 | };
23 |
24 |
25 | //uncomment here to use database
26 | //firebase.initializeApp(config);
27 |
28 |
29 | //the keys in state that we care about storing
30 | const keys = [
31 | 'encodedSequences',
32 | 'sequenceUUID',
33 | 'selectedIndex',
34 | 'sequence',
35 | 'bpm',
36 | 'playMode',
37 | 'path',
38 | 'pathIntersections',
39 | 'pathLerp',
40 | 'puck',
41 | 'gradient',
42 | 'grid'
43 | ];
44 |
45 | const parseState = (state)=>
46 | keys.reduce((mem, key)=>{
47 | mem[key] = state[key];
48 | return mem;
49 | }, {});
50 |
51 |
52 | export const save = (state)=>{
53 | const id = uuid();
54 | return firebase.database().ref(`shares/${id}`)
55 | .set(parseState(state))
56 | .then(function(){ console.log(arguments); return id; });
57 | };
58 |
59 | export const get = (uid='')=>
60 | firebase.database().ref(`shares/${uid}`).once('value');
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/js/get-mouse-position.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | * get-mouse-position is a reliable way to get the current mouse
17 | * position relative to the element provided, considering all offest
18 | * @example getMousePosition(domElement, event): {x, y}
19 | */
20 |
21 | //window has a circular window.window reference
22 | var isWindow = function( elem ){
23 | return elem !== null && elem === elem.window;
24 | };
25 |
26 | var getWindow = function( elem ){
27 | return isWindow(elem) ? elem : elem.nodeType === 9 ? elem.defaultView || elem.parentWindow : false;
28 | };
29 |
30 | //calculate the page-offset of the element
31 | /**
32 | * calculate the offset of an element
33 | * @param {HTMLElement} element
34 | * @return { x:Number, y: Number }
35 | */
36 | export function offset( elem, ignoreWindowOffset ){
37 | //true if not explicitly false
38 | ignoreWindowOffset = (ignoreWindowOffset === true);
39 | var docElem,
40 | win,
41 | box = {
42 | top: 0,
43 | left: 0
44 | },
45 | doc = elem && elem.ownerDocument;
46 |
47 | box.x = box.left;
48 | box.y = box.top;
49 |
50 | if (!doc) {
51 | return box;
52 | }
53 |
54 | docElem = doc.documentElement;
55 |
56 | // Make sure it's not a disconnected DOM node
57 | if (!document.body.contains(elem)) {
58 | return box;
59 | }
60 |
61 | // If we don't have gBCR, just use 0,0 rather than error
62 | // BlackBerry 5, iOS 3 (original iPhone)
63 | if (typeof elem.getBoundingClientRect !== 'undefined') {
64 | box = elem.getBoundingClientRect();
65 | box.x = box.left;
66 | box.y = box.top;
67 | }
68 | win = getWindow(doc);
69 | var page = { x: 0, y: 0 };
70 | if( !ignoreWindowOffset ){
71 | page.y = win.pageYOffset || docElem.scrollTop;
72 | page.x = win.pageXOffset || docElem.scrollLeft;
73 | }
74 |
75 | const box2 = {};
76 | Object.assign(box2, box);
77 |
78 | box2.top = box.y = box.top + page.y - (docElem.clientTop || 0);
79 | box2.left = box.x = box.left + page.x - (docElem.clientLeft || 0);
80 | /*box.top = box.y = box.top + win.pageYOffset - docElem.clientTop;
81 | box.left = box.x = box.left + win.pageXOffset - docElem.clientLeft;*/
82 |
83 | return box2;
84 | }
85 |
86 |
87 | /**
88 | * get the mouse position within the provided HTMLElement
89 | * @param {HTMLElement} element
90 | * @param {Event} event this requires to an event object
91 | * @param {Boolean} [ignoreWindowOffset] optionally ignore the window.pageYOffset
92 | * @return { x:Number, y:Number, toString:Function }
93 | */
94 | export default function getMousePosition(element, event, ignoreWindowOffset, point={} ){
95 | const off = offset(element, ignoreWindowOffset);
96 | if( event.touches && event.touches.length === 1 ){
97 | event = event.touches[0];
98 | }
99 |
100 | point.x = event.clientX - off.left;
101 | point.y = event.clientY - off.top;
102 | return point;
103 | }
104 |
--------------------------------------------------------------------------------
/js/hub.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import eventMap from 'event-map';
16 | import assert from 'assert';
17 | import { generate as uuid } from 'shortid';
18 | import deepMixin from 'mixin-deep';
19 | import deepExtend from 'deep-extend';
20 | import { set as setObjectPath } from 'object-path';
21 |
22 | Object.freeze = Object.freeze || (()=>{});
23 |
24 |
25 | /**
26 | * this module is a home-rolled minimal mvc manager
27 | */
28 | export default function app({ options, state, computed }){
29 |
30 | options = options || {};
31 | computed = computed || {};
32 |
33 | const DEBUG = !!options.debug;
34 | const IMMUTABLE = !!options.immutable;
35 |
36 | const removeEventsMap = {};
37 | const uuidMap = {};
38 |
39 | const findUuid = (view)=>{
40 | for(let key in uuidMap){
41 | if(uuidMap[key] === view){
42 | return key;
43 | }
44 | }
45 | };
46 |
47 | const getNextState = (changes)=>
48 | applyComputed((IMMUTABLE ? deepExtend : deepMixin)({}, app.state, changes));
49 |
50 | //Object.freeze(state);
51 |
52 | //start dirty, first render should be (state, {})
53 | let stateIsDirty = true;
54 |
55 | const views = [];
56 |
57 | //this is what gets exported
58 | const app = {
59 | lastState: {},
60 | state: {},
61 | views,
62 | set,
63 | setDeep,
64 | onStart,
65 | onStop,
66 | addView,
67 | removeView,
68 | render,
69 | toJSON
70 | };
71 |
72 |
73 | app.set(state);
74 |
75 | function applyComputed(state){
76 | for(let prop in computed){
77 | setObjectPath(state, prop, computed[prop](state, app.lastState));
78 | }
79 | return state;
80 | }
81 |
82 | /**
83 | * provide a pattern to a single deep property
84 | * @example setDeep('gradient.0.3', 1) //will set state.gradient[0][3] = 1
85 | * @param pattern
86 | * @param value
87 | * @param cb
88 | */
89 | function setDeep(pattern, value, cb=(()=>{})){
90 | let before, after;
91 | if(DEBUG) {
92 | before = performance.now();
93 | }
94 | const nextState = getNextState();
95 | setObjectPath(nextState, pattern, value);
96 | app.state = nextState;
97 | stateIsDirty = true;
98 | if(DEBUG) {
99 | after = performance.now();
100 | console.log(`set deep took ${after - before}ms`);
101 | }
102 | cb(app.state);
103 | }
104 |
105 | /**
106 | * provide an object of changes to merge into the current state, overwriting any existing
107 | * @param changes
108 | * @param cb
109 | */
110 | function set(changes, cb=(()=>{})){
111 | //go through and deep-merge changes
112 | let before, after;
113 | if(DEBUG) {
114 | before = performance.now();
115 | }
116 | const nextState = getNextState(changes);
117 | //const stateDiff = diff(state, nextState);
118 | if(DEBUG){
119 | after = performance.now();
120 | console.log(`${after-before} ms elapsed`);
121 | }
122 | app.state = nextState;
123 | //app.state = Object.freeze(nextState);
124 | stateIsDirty = true;
125 | cb(app.state);
126 | }
127 |
128 | /**
129 | * add a view, take its event map and listen for it, providing it with state
130 | * whenever the event occurs
131 | * @param view
132 | * @returns {{
133 | * lastState:{},
134 | * state:{},
135 | * views:Array,
136 | * set:Function,
137 | * addView:Function,
138 | * removeView:Function,
139 | * render:Function
140 | * }}
141 | */
142 | function addView(view){
143 | if(Array.isArray(view)){
144 | //accept receiving multiple views as Array
145 | view.forEach(addView);
146 | return app;
147 | }
148 |
149 | assert.equal(views.indexOf(view), -1, `View ${view} already exists`);
150 |
151 | const id = uuid();
152 |
153 | uuidMap[id] = view;
154 |
155 | const events = {};
156 | for(let prop in view.events){
157 | events[prop] = (event)=> view.events[prop](event, app.state, app.lastState);
158 | }
159 |
160 | if(Object.keys(events).length) {
161 | //every view has a uuid and that will be used for registering the event map
162 | removeEventsMap[id] = view.domElement ? eventMap(view.domElement, events) : eventMap(events);
163 | }
164 |
165 | views.push(view);
166 | return app;
167 | }
168 |
169 | /**
170 | * remove a view, clean up its listeners as well
171 | * @param view
172 | * @returns {{
173 | * lastState:{},
174 | * state:{},
175 | * views:Array,
176 | * set:Function,
177 | * addView:Function,
178 | * removeView:Function,
179 | * render:Function
180 | * }}
181 | */
182 | function removeView(view){
183 | const index = views.indexOf(view);
184 | const id = findUuid(view);
185 | assert.notEqual(index, -1, `View ${view} does not exist`);
186 | assert(!!id, 'View uuid could not be found');
187 | const removeEvents = removeEventsMap[id];
188 | removeEvents && removeEvents();
189 | view.remove && view.remove();
190 | views.splice(index, 1);
191 | return app;
192 | }
193 |
194 | function onStart(){
195 | for(let view of views){
196 | view.onStart && view.onStart(app.state, app.lastState);
197 | }
198 | }
199 |
200 | function onStop(){
201 | for(let view of views){
202 | view.onStop && view.onStop(app.state, app.lastState);
203 | }
204 | }
205 |
206 |
207 | function render(){
208 | if(!stateIsDirty){
209 | return;
210 | }
211 | for(let i=0; i {
28 | assert.equal(typeof onChange, 'function', `requires a function to report changes to, received ${onChange}`);
29 |
30 | const updateMidiOutState = () => {
31 | onChange(null, midiDevices);
32 | };
33 |
34 | if(typeof navigator.requestMIDIAccess !== 'function'){
35 | onChange(new Error('navigator.requestMIDIAccess does not exist'));
36 | return;
37 | }
38 |
39 | navigator.requestMIDIAccess().then((midi) => {
40 |
41 | midi.outputs.forEach((output) => {
42 | /*console.log(`
43 | Output midi device [type: '${output.type}']
44 | id: ${output.id}
45 | manufacturer: ${output.manufacturer}
46 | name:${output.name}
47 | version: ${output.version}`);*/
48 | midiDevices[output.name] = output;
49 | });
50 |
51 | midi.onstatechange = (e) => {
52 | if(e.port.state == 'disconnected') {
53 | delete midiDevices[e.port.name];
54 | updateMidiOutState();
55 | } else if(e.port.state == 'connected') {
56 | if(!(e.port.name in midiDevices)) {
57 | midi.outputs.forEach((output) => {
58 | if(output.name == e.port.name){
59 | midiDevices[e.port.name] = output;
60 | updateMidiOutState();
61 | }
62 | });
63 | }
64 | }
65 | };
66 | updateMidiOutState();
67 | }, onChange);
68 | };
69 |
70 | /**
71 | * send a MIDI Note to a MIDI Device
72 | * @param {String} outputDeviceName the device to use
73 | * @param {Number} outnoteNum the note to send
74 | * @param {Boolean} shouldTurnNoteOn are we turning this note on or off?
75 | * @param {Number} currVelocity velocity to send note at
76 | * @param {Number} channel
77 | */
78 | export const sendMIDIToDevice = (outputDeviceName, outnoteNum, shouldTurnNoteOn, currVelocity, channel) => {
79 | const outputDevice = midiDevices[outputDeviceName];
80 | assert(outputDevice, `MIDI Device ${outputDeviceName} does not exist`);
81 | const eventToSend = shouldTurnNoteOn ? MIDI_EVENT_ON : MIDI_EVENT_OFF;
82 | outputDevice.send([eventToSend + channel - 1, outnoteNum, 0x03]);
83 | };
84 |
85 |
--------------------------------------------------------------------------------
/js/models/color.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import { lerpArray, times } from '../utils';
17 | import assert from 'assert';
18 |
19 | /**
20 | * Generate a gradient that interopolates across 2 dimensions
21 | * @param {Array} tl top-left color
22 | * @param {Array} tr top-right color
23 | * @param {Array} bl bottom-left color
24 | * @param {Array} br bottom-right color
25 | * @param {Number} columns
26 | * @param {Number} rows
27 | */
28 | export const generate4PointGradient = (tl, tr, bl, br, columns, rows)=>{
29 | return times(columns, (x,columns)=>{
30 | const cp = x / (columns-1);
31 | const topColor = lerpArray(tl, tr, cp);
32 | const bottomColor = lerpArray(bl, br, cp);
33 |
34 | return times(rows, (y, rows)=>{
35 | const rp = y/ (rows-1);
36 | return lerpArray(topColor, bottomColor, rp);
37 | });
38 | });
39 | };
40 |
41 |
42 | // reuse these arrays always to avoid extra garbage collection
43 | const lerpTmpTop = [];
44 | const lerpTmpBot = [];
45 |
46 | const shrinkToLength = (arr, length)=>{
47 | let attempts = 0;
48 | const maxAttempts = 10000;
49 | while(arr.length > length && attempts < maxAttempts){
50 | arr.pop();
51 | attempts++;
52 | }
53 | assert(attempts < maxAttempts, 'maxAttempts reached, Wow, somehow that array got really full');
54 | return arr;
55 | };
56 |
57 | /**
58 | * generate a 4-point gradient for one specified cell
59 | * @param {Array} tl top-left color
60 | * @param {Array} tr top-right color
61 | * @param {Array} bl bottom-left color
62 | * @param {Array} br bottom-right color
63 | * @param {Number} percentX percent between 0-1
64 | * @param {Number} percentY perecent between 0-1
65 | * @returns {Array}
66 | */
67 | export const generate4PointGradientAt = (tl, tr, bl, br, percentX, percentY, result=[])=>{
68 | //empty any extras (this shouldn't ever actually happen)
69 | shrinkToLength(lerpTmpTop, tl.length);
70 | shrinkToLength(lerpTmpBot, tl.length);
71 | const topColor = lerpArray(tl, tr, percentX, lerpTmpTop);
72 | const bottomColor = lerpArray(bl, br, percentX, lerpTmpBot);
73 | return lerpArray(topColor, bottomColor, percentY, result);
74 | };
75 |
76 |
77 | /**
78 | * Generate a gradient that
79 | * @param {Array} tl top-left color
80 | * @param {Array} tr top-right color
81 | * @param {Array} bl bottom-left color
82 | * @param {Array} br bottom-right color
83 | * @param {Array} center center color
84 | * @param {Number} columns
85 | * @param {Number} rows
86 | */
87 | export const generate5PointGradient = (tl, tr, bl, br, center, columns, rows)=>{
88 | return times(columns, (x,columns)=>{
89 | const cp = x / (columns-1);
90 | const topColor = lerpArray(tl, tr, cp);
91 | const bottomColor = lerpArray(bl, br, cp);
92 |
93 | return times(rows, (y, rows)=>{
94 | const rp = y/ (rows-1);
95 | const color = lerpArray(topColor, bottomColor, rp);
96 | const dc = (x - ~~(columns/2)) / columns;
97 | const dr = (y - ~~(rows/2)) / rows;
98 | const dist = Math.sqrt(dc*dc + dr*dr);
99 |
100 | return lerpArray(color, center, 1.0 - dist*2);
101 | });
102 | });
103 | };
104 |
105 |
106 | const numberComparator = (f1,f2)=>{
107 | if(f1 == f2) return 0;
108 | if(f1 < f2) return -1;
109 | if(f1 > f2) return 1;
110 | };
111 |
112 | const INV60DEGREES = 60.0 / 360;
113 |
114 | export const rgbToHSV = ([r, g, b])=>{
115 | const hsv = [];
116 | var h = 0,
117 | s = 0,
118 | v = Math.max(r, g, b),
119 | d = v - Math.min(r, g, b);
120 |
121 | if (v !== 0) {
122 | s = d / v;
123 | }
124 |
125 | if (s !== 0) {
126 | if( numberComparator( r, v ) === 0 ){
127 | h = (g - b) / d;
128 | } else if ( numberComparator( g, v ) === 0 ) {
129 | h = 2 + (b - r) / d;
130 | } else {
131 | h = 4 + (r - g) / d;
132 | }
133 | }
134 | h *= INV60DEGREES;
135 | if (h < 0) {
136 | h += 1.0;
137 | }
138 | hsv[0] = h;
139 | hsv[1] = s;
140 | hsv[2] = v;
141 |
142 | return hsv;
143 | };
144 |
145 |
146 |
147 | /**
148 | * Converts HSV values into RGB array.
149 | * @param h
150 | * @param s
151 | * @param v
152 | * @return rgb array
153 | */
154 | export const hsvToRGB = ([h, s, v])=>{
155 | const rgb = [];
156 | if(s === 0.0){
157 | rgb[0] = rgb[1] = rgb[2] = v;
158 | } else {
159 | h /= INV60DEGREES;
160 | var i = parseInt(h,10),
161 | f = h - i,
162 | p = v * (1 - s),
163 | q = v * (1 - s * f),
164 | t = v * (1 - s * (1 - f));
165 |
166 | if (i === 0) {
167 | rgb[0] = v;
168 | rgb[1] = t;
169 | rgb[2] = p;
170 | } else if (i == 1) {
171 | rgb[0] = q;
172 | rgb[1] = v;
173 | rgb[2] = p;
174 | } else if (i == 2) {
175 | rgb[0] = p;
176 | rgb[1] = v;
177 | rgb[2] = t;
178 | } else if (i == 3) {
179 | rgb[0] = p;
180 | rgb[1] = q;
181 | rgb[2] = v;
182 | } else if (i == 4) {
183 | rgb[0] = t;
184 | rgb[1] = p;
185 | rgb[2] = v;
186 | } else {
187 | rgb[0] = v;
188 | rgb[1] = p;
189 | rgb[2] = q;
190 | }
191 | }
192 | return rgb;
193 | };
194 |
195 |
196 | export const toCSSString = (color)=>
197 | `rgba(${~~color[0]},${~~color[1]},${~~color[2]}, ${(color[3]||1)})`;
198 |
--------------------------------------------------------------------------------
/js/models/modals.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | export const NONE = '';
17 | export const ABOUT = 'about';
18 | export const SHARE = 'share';
19 |
--------------------------------------------------------------------------------
/js/models/play-modes.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | //the user is dragging the puck around 1-cell at a time
16 | export const DRAG = 'drag';
17 | //the user has a path or is creating a paththat is being played in sequence
18 | export const PATH = 'path';
19 |
--------------------------------------------------------------------------------
/js/models/responsive.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | * this modules responsibility is to set breakpoints for the view and apply a css-style
17 | * for its appropriate dimensions
18 | */
19 |
20 |
21 | export const DESKTOP = 'desktop';
22 | export const MOBILE_PORTRAIT = 'mobile-portrait';
23 | export const MOBILE_LANDSCAPE = 'mobile-landscape';
24 | export const TABLET = 'tablet';
25 |
26 |
27 | const queries = [
28 | ['(max-width: 479px)', MOBILE_PORTRAIT],
29 | ['(orientation: landscape) and (max-height: 440px)', MOBILE_LANDSCAPE],
30 | ['(max-width: 991px)', TABLET]
31 | ];
32 |
33 | export function is(layout){
34 | return get() === layout;
35 | }
36 |
37 | export function get(){
38 | if(!window.matchMedia){
39 | //possibly a really old browser, if so its desktop
40 | return DESKTOP;
41 | }
42 |
43 | for(let i=0; i}
38 | */
39 | export const urls = notesBySample.map(notes=> `/ai/beat-blender/view/assets/audio/drums/${notes[0]}.mp3`);
40 |
41 | /**
42 | * this is a map of every unique note to the array-index it is found in
43 | * so if its value is "3" then play `urls[3]`
44 | */
45 | const noteFlatMap = notesBySample.reduce((mem, notes, i)=>{
46 | notes.forEach(note=> mem[note] = i);
47 | return mem;
48 | }, {});
49 |
50 |
51 | /**
52 | * get the index in the urls array for the given note
53 | * @return {Number}
54 | */
55 | export const getURLIndexForNote = (note)=> noteFlatMap[note];
56 |
57 | const map = {
58 | 36: 0,
59 | 38: 1,
60 | 42: 2,
61 | 46: 3,
62 | 45: 4,
63 | 48: 5,
64 | 50: 6,
65 | 49: 7,
66 | 51: 8
67 | };
68 |
69 | const revMap = {
70 | 0: 36,
71 | 1: 38,
72 | 2: 42,
73 | 3: 46,
74 | 4: 45,
75 | 5: 48,
76 | 6: 50,
77 | 7: 49,
78 | 8: 51
79 | };
80 |
81 | export const getDrumRowFromNotePitch = (pitch)=> map[pitch];
82 | export const getMidiNoteFromDrumRow = (row)=> revMap[row];
83 |
84 |
85 | /**
86 | * calculate the sequencers matrix values (0|1) for each column and row
87 | * @param {Array<{startTime:Number, pitch:Number}>} notes
88 | * @param {Number} columns
89 | * @param {Number} rows
90 | * @param {Array>} [matrix] optionally provide a matrix to reuse
91 | * @returns {Array>}
92 | */
93 | export const notesToMatrix = (notes, columns, rows, matrix)=>{
94 | assert(Array.isArray(notes), `notes should be array, received ${notes}`);
95 | assert.equal(typeof columns, 'number', `invalid columns ${columns}`);
96 | assert.equal(typeof rows, 'number', `invalid rows ${columns}`);
97 | //2d array of all 0s matching our current matrix size
98 | matrix = matrix || times(columns, ()=>times(rows,()=>0));
99 |
100 | notes.forEach((note, column) => {
101 | const notes = getLabelsFromEncoding(note, columns);
102 | notes.forEach((row) => {
103 | matrix[column][row] = 1;
104 | });
105 | });
106 | return matrix;
107 | };
108 |
109 | export const iNoteSequenceToEncodedNotes = (sequences, columns)=>{
110 | const encodedSequences = times(sequences.length, ()=>times(columns,()=>0));
111 | sequences.forEach((sequence, sequenceIndex) => {
112 | sequence.notes.forEach(note => {
113 | encodedSequences[sequenceIndex][note.quantizedStartStep] += Math.pow(2, getDrumRowFromNotePitch(note.pitch));
114 | });
115 | });
116 | return encodedSequences;
117 | };
118 |
119 | export const encodedNotesToINoteSequence = (notes, columns)=>{
120 | assert(Array.isArray(notes), `notes should be array, received ${notes}`);
121 | //2d array of all 0s matching our current matrix size
122 | let sequenceNotes = [];
123 | notes.forEach((note, column) => {
124 | const notes = getLabelsFromEncoding(note, columns);
125 | notes.forEach((row) => {
126 | sequenceNotes.push({pitch: getMidiNoteFromDrumRow(row), quantizedStartStep: column});
127 | // matrix[column][row] = 1;
128 | });
129 | });
130 | return {notes: sequenceNotes};
131 | };
132 |
133 | /**
134 | * expands a given value to retrive the lables
135 | * @param {Number} value the encoded value to expand
136 | * @param {Number} numRows height of the initially encoded column
137 | * @returns {Array} decoded lables
138 | */
139 | export const getLabelsFromEncoding = (value, numRows) => {
140 | let labels = [];
141 | for (var i = 0; i < numRows; i++) {
142 | if(((value >> i) & 1) == 1) {
143 | labels.push(i);
144 | }
145 | }
146 | return labels;
147 | };
148 |
149 |
--------------------------------------------------------------------------------
/js/utils.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | export const copyToClipboard = (target)=>{
17 | var currentFocus = document.activeElement;
18 | target.select();
19 | target.setSelectionRange(0, target.value.length);
20 |
21 | // copy the selection
22 | var succeed;
23 | try {
24 | succeed = document.execCommand('copy');
25 | console.log(succeed);
26 | } catch(e) {
27 | succeed = false;
28 | console.log(e);
29 | }
30 | // restore original focus
31 | if (currentFocus && typeof currentFocus.focus === 'function') {
32 | currentFocus.focus();
33 | }
34 |
35 | return succeed;
36 | };
37 |
38 | /**
39 | * true if these objects have the same shallow value for the key provided
40 | * @param {Object} a
41 | * @param {Object} b
42 | * @param {string} key
43 | * @return {boolean} true if key is equal to each other
44 | */
45 | export const keyEqual = (a, b, key)=> a[key] === b[key];
46 |
47 |
48 | /**
49 | * true if these objects have a different shallow value for the key provided
50 | * @param {Object} a
51 | * @param {Object} b
52 | * @param {string} key
53 | * @return {boolean} true if key is not equal to each other
54 | */
55 | export const keyNotEqual = (a, b, key)=> !keyEqual(a, b, key);
56 |
57 |
58 | export const allKeysEqual = (a, b, keyArray)=>{
59 | for(let i=0; i
77 | !!(keyArray || Object.keys(a)).filter(k=> keyNotEqual(a, b, k)).length;
78 |
79 |
80 | export const clamp = (val, min, max)=> Math.max(Math.min(val, max), min);
81 |
82 |
83 | /**
84 | * linear interpolation
85 | * @param {Number} start
86 | * @param {Number} end
87 | * @param {Number} amt
88 | * @returns {Number}
89 | */
90 | export const lerp = (start, end, amt) =>
91 | (1 - amt) * start + amt * end;
92 |
93 | /**
94 | * Linearly interpolate a 2D vector
95 | * @param {{x:Number, y:Number}} start
96 | * @param {{x:Number, y:Number}} end
97 | * @param {Number} amt
98 | * @returns {{x:Number, y:Number}}
99 | */
100 | export const lerpPoint = (start, end, amt) =>
101 | ({
102 | x: (1 - amt) * start.x + amt * end.x,
103 | y: (1 - amt) * start.y + amt * end.y
104 | });
105 |
106 |
107 | /**
108 | * lerp 2 arrays
109 | * example: lerpArray([255, 128, 64], [0, 0, 0], 0.5) -> [128, 64, 32]
110 | * @param {Array} arrA
111 | * @param {Array} arrB
112 | * @param {Number} amt
113 | * @param {Array} [arrC] optionally provide the result array
114 | */
115 | export const lerpArray = (arrA, arrB, amt, arrC=[])=>{
116 | const len = Math.min(arrA.length, arrB.length);
117 | for(let i=0; i {
130 | const dx = a.x - b.x;
131 | const dy = a.y - b.y;
132 | return Math.sqrt(dx * dx + dy * dy);
133 | };
134 |
135 |
136 | /**
137 | * Given `points` find the closest to `pt`
138 | * @param {Array<{x:Number, y:Number}>} points
139 | * @param {{x:Number, y:Number}} pt
140 | * @returns {x:Number, y:Number}}
141 | */
142 | export const closestPoint = (points, pt) => {
143 | let closestPoint = null;
144 | let closestDistance = Number.MAX_VALUE;
145 | points.forEach((currPoint) => {
146 | const dist = distance(pt, currPoint);
147 | if (dist < closestDistance) {
148 | closestPoint = currPoint;
149 | closestDistance = dist;
150 | }
151 | });
152 | return closestPoint;
153 | };
154 |
155 |
156 | export const hash = (x) => {
157 | var nx = x * 1.380251;
158 | var n = Math.floor(nx);
159 | var f = nx - n;
160 | var h = 355.347391 * f + n * 5.3794610581 + 41.53823;
161 | h = h * h + f * h + f * f * 37.3921539 + 0.3861203;
162 | var nf = Math.floor(h);
163 | return h - nf;
164 | };
165 |
166 | export const smoothNoise = (x) => {
167 | var n = Math.floor(x);
168 | var f = x - n;
169 | var n2 = n + 1;
170 | var h1 = hash(n);
171 | var h2 = hash(n2);
172 | var smooth = f * f * (3 - 2 * f);
173 | return h1 * (1 - smooth) + h2 * smooth;
174 | };
175 |
176 | /**
177 | * generate fractal noise
178 | * @param {Number} x
179 | * @returns {number}
180 | */
181 | export const fractalNoise = (x) => {
182 | var p = x + 11.3951031;
183 | var amp = 0.7;
184 | var scale = 10.0;
185 | var result = 0.0;
186 | for (var i = 0; i < 6; i++) {
187 | result += amp * smoothNoise(p * scale);
188 | amp *= 0.5;
189 | scale *= 2.0;
190 | }
191 |
192 | return result;
193 | };
194 |
195 |
196 | /**
197 | * Used to generate an array of numbers between `start` and `stop`
198 | * i.e. range(1, 5) = [1,2,3,4]
199 | * @param {Number} start
200 | * @param {Number} stop
201 | * @returns {Array}
202 | */
203 | export const range = function(start, stop){
204 | //if only one argument is provided it was the stop
205 | if (arguments.length === 1) {
206 | stop = start;
207 | start = 0;
208 | }
209 | const arr = [];
210 | for (; start < stop; start++) {
211 | arr.push(start);
212 | }
213 | return arr;
214 | };
215 |
216 | /**
217 | * invoke `fn`, `n` times and collect the result
218 | * @param {Number} n
219 | * @param {Function} fn
220 | * @returns {Array}
221 | */
222 | export const times = (n, fn)=>{
223 | const result = [];
224 | for(let i=0; i{
232 | out.x = lerp(a.x, b.x, t);
233 | out.y = lerp(a.y, b.y, t);
234 | return out;
235 | };
236 | /**
237 | * map a value from one range of numbers to another,
238 | * i.e. scalemap(0.5, 0, 2, 10, 20) = 15
239 | * @param value
240 | * @param start1
241 | * @param stop1
242 | * @param start2
243 | * @param stop2
244 | * @returns {*}
245 | */
246 | export const scalemap = ( value, start1, stop1, start2, stop2 )=>
247 | start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));
248 |
249 | export const pathLength = (path)=>
250 | path.reduce((sum, pt, i, arr)=>
251 | i===0 ? sum : sum + distance(arr[i-1], arr[i]), 0);
252 |
253 |
254 | /**
255 | * find the point at `t` along the `path` points
256 | * @param {Array<{x:Number, y:Number}>} path
257 | * @param {Number} t
258 | * @param {Object} [out] optionally provide an object to mutate
259 | * @returns {Object}
260 | */
261 | export const lerpPath = (path, t, out={})=>{
262 |
263 | t = clamp(t, 0, 1);
264 |
265 | if(t === 0 || path.length < 2){
266 | return path[0];
267 | }
268 | if(t === 1){
269 | return path[path.length-1];
270 | }
271 |
272 | const totalLength = pathLength(path);
273 | const wantedLength = totalLength * t;
274 |
275 | let lastLength = 0;
276 | let currLength = 0;
277 | let a, b;
278 |
279 | for(let i=1; i= wantedLength){
285 | break;
286 | }
287 | lastLength = currLength;
288 | }
289 |
290 | const relativeLerp = scalemap(wantedLength, lastLength, currLength, 0, 1);
291 |
292 | return lerpBetweenPoints(a, b, relativeLerp, out);
293 | };
294 |
295 |
--------------------------------------------------------------------------------
/js/views/base-view.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import { EventEmitter } from 'events';
16 | import assert from 'assert';
17 |
18 |
19 | export const getDOM = (dom)=>
20 | typeof dom === 'string' ?
21 | document.querySelector(dom) :
22 | dom;
23 |
24 |
25 |
26 | export class View extends EventEmitter {
27 |
28 | constructor(domElement){
29 | super();
30 | this.domElement = getDOM(domElement);
31 | assert(!!this.domElement, `Unable to resolve domElement from ${domElement}`);
32 | }
33 |
34 | set visible(val){
35 | if(val !== this.visible){
36 | this.domElement.classList[val ? 'remove' : 'add']('hidden');
37 | }
38 | }
39 |
40 | get visible(){
41 | return !this.domElement.classList.contains('hidden');
42 | }
43 |
44 |
45 | _setEventMap(map){
46 | this.events = map;
47 | //this.__removeEventListeners = eventMap(this.domElement, map);
48 | }
49 |
50 | shouldComponentUpdate(){
51 | return true;
52 | }
53 |
54 | render(){
55 | return this;
56 | }
57 |
58 | removeEventListeners(){
59 | this.__removeEventListeners && this.__removeEventListeners();
60 | }
61 |
62 | remove(){
63 | this.removeEventListeners();
64 | this.domElement.parentElement && this.domElement.parentElement.removeChild(this.domElement);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/js/views/button.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import debounce from 'debounce';
16 |
17 | import { View } from './base-view';
18 | import throttle from 'throttleit';
19 | import * as playModes from '../models/play-modes';
20 | import { anyKeyNotEqual } from '../utils';
21 |
22 | const editTemplate = ()=>`
23 | UNDO
24 | CLEAR `;
25 |
26 |
27 | export class EditModeGroup extends View {
28 |
29 | constructor(domElement){
30 | super(domElement);
31 | this._setEventMap({
32 | 'click .save-edit': ()=> this.emit('save', this),
33 | 'click .undo-edit': ()=>this.emit('undo', this),
34 | 'click .clear-edit': ()=>this.emit('clear', this)
35 | });
36 | }
37 |
38 | shouldComponentUpdate(state, last) {
39 | const sci = state.selectedCornerIndex;
40 | const lsci = last.selectedCornerIndex;
41 | return sci != lsci;// || (state.editHistory[sci] && (state.editHistory[sci][0] !== last.editHistory[sci][0]));
42 | }
43 |
44 | render(state) {
45 |
46 | if(state.selectedCornerIndex > -1) {
47 | this.domElement.classList.add('active');
48 | } else {
49 | this.domElement.classList.remove('active');
50 | }
51 |
52 | this.domElement.innerHTML = editTemplate(state);
53 | }
54 | }
55 |
56 |
57 | export class ToggleButton extends View {
58 | constructor(domElement, shouldBeActive){
59 | super(domElement);
60 | this._shouldBeActive = shouldBeActive;
61 | this.__active = false;
62 |
63 | this._setEventMap({
64 | 'click': ()=> this.emit('click', this)
65 | });
66 | }
67 |
68 | set active(val){
69 | const c = 'active';
70 | if(val !== this.domElement.classList.contains(c)){
71 | this.domElement.classList[val ? 'add' : 'remove'](c);
72 | }
73 | }
74 |
75 | get active(){
76 | return this.domElement.classList.contains('active');
77 | }
78 |
79 | render(state, last){
80 | this.active = this._shouldBeActive(state, last);
81 | return this;
82 | }
83 | }
84 |
85 |
86 |
87 |
88 |
89 | export class CustomizeBeatsButton extends ToggleButton {
90 |
91 | constructor(domElement, shouldBeActive){
92 | super(domElement, shouldBeActive);
93 | // this.domElement.innerHTML = bpmSliderTemplate();
94 | this._setEventMap({
95 | //dont let this be repeatedly clicked quickly
96 | 'click' : debounce((event, state) => {
97 | if(state.selectedCornerIndex >=0) {
98 | this.emit('done', this);
99 | } else {
100 | this.emit('edit', this);
101 | }
102 |
103 | }, 120, true)
104 | });
105 | }
106 |
107 | shouldComponentUpdate(state, last) {
108 | return state.selectedCornerIndex !== last.selectedCornerIndex ||
109 | state.gridAnimationLerp !== last.gridAnimationLerp ||
110 | state.interpolating !== last.interpolating;
111 | }
112 |
113 | render(state) {
114 |
115 | const isBusy = state.interpolating || state.gridAnimationLerp > 0 && state.gridAnimationLerp < 1;
116 | //if the grid is animating, dont let the button be clicked
117 | this.domElement.classList[ isBusy ? 'add' : 'remove' ]('disabled');
118 |
119 | // if(state.selectedCornerIndex === last.selectedCornerIndex){
120 | // //already up to date
121 | // return;
122 | // }
123 | if(isBusy) {
124 | this.domElement.innerHTML = 'LOADING...';
125 | } else if(state.selectedCornerIndex >=0) {
126 | this.domElement.innerHTML = 'DONE';
127 | this.domElement.classList.add('active');
128 | } else {
129 | this.domElement.innerHTML = 'EDIT CORNERS';
130 | this.domElement.classList.remove('active');
131 | }
132 | }
133 | }
134 |
135 |
136 | const dragDrawTemplate = (labelA, labelB)=>`
137 | ${labelA}
138 |
141 | ${labelB} `;
142 |
143 |
144 |
145 | export class DragDrawToggle extends View {
146 | constructor(domElement){
147 | super(domElement);
148 | this.domElement.innerHTML = dragDrawTemplate('DRAG', 'DRAW');
149 | this._setEventMap({
150 | 'click': ()=> this.emit('click', this)
151 | });
152 | }
153 |
154 |
155 | shouldComponentUpdate(state, last){
156 | return anyKeyNotEqual(state, last, ['selectedCornerIndex', 'playMode']);
157 | }
158 |
159 | render({ playMode, selectedCornerIndex }){
160 | //const { selectedCornerIndex } = state;
161 | this.domElement.classList[ playMode === playModes.PATH ? 'add' : 'remove' ]('right-selected');
162 | this.domElement.classList[ selectedCornerIndex === -1 ? 'add' : 'remove']('active');
163 | /*const isOn = selectedCornerIndex > -1;
164 | Object.assign(this.domElement.style, {
165 | pointerEvents: isOn ? 'all' : 'none',
166 | opacity: isOn ? 0.5 : 1,
167 | cursor: isOn ? 'pointer' : 'inherit'
168 | });*/
169 |
170 | return this;
171 | }
172 | }
173 |
174 |
175 | const bpmSliderTemplate = ()=>`
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 | 120
187 |
`;
188 |
189 |
190 | export class BPMSlider extends ToggleButton {
191 |
192 | constructor(domElement, shouldBeActive){
193 | super(domElement, shouldBeActive);
194 | this.domElement.innerHTML = bpmSliderTemplate();
195 | this.pendulum = document.getElementById('pendulumWrapper');
196 | this.__label = document.querySelector('.bpm-slider-label');
197 | this._setEventMap({
198 | 'click .bpm-slider-button': ()=> this.emit('click', this),
199 | //when the bpm slider moves
200 | 'input input[type="range"]': throttle((event)=> {
201 | let bpmValue = parseInt(event.target.value, 10);
202 | this.emit('change', this, bpmValue);
203 | }, 1000 / 15)
204 | });
205 | }
206 |
207 | // shouldComponentUpdate(state, last) {
208 | // if(last.sequence === undefined) return false;
209 | // return state.sequence.activeColumn !== last.sequence.activeColumn;
210 | // }
211 |
212 | render(state, last){
213 | if(state.bpm !== last.bpm) {
214 | this.__label.innerHTML = state.bpm;
215 | }
216 |
217 | //percent through the sequence * PI
218 | const perc = state.sequence.activeColumn / state.sequence.columns * Math.PI;
219 | // there are 4 beats per measure
220 | const beats = 4;
221 | //how many degrees should this fluctuate (on each side of the cneter)
222 | const amp = 45;
223 |
224 | //add the amp at the end so its based on the center
225 | const angle = (Math.sin(perc * beats) ) * amp + amp;
226 |
227 | this.pendulum.style.transform = `rotate(${angle}deg)`;
228 | return super.render(state, last);
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/js/views/debug-layout-grid.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import * as grid2d from 'grid2d';
16 | import { View } from './base-view';
17 |
18 | /**
19 | * render the `state.layoutGrid` on top of the page,
20 | * useful for debugging positioning at different resolutions
21 | * this module is mainly just for fun tbh :)
22 | */
23 |
24 |
25 | export class DebugLayoutGrid extends View {
26 |
27 | constructor(color='rgba(255,128,128,1)'){
28 | super(document.createElement('canvas'));
29 | this.ctx = this.domElement.getContext('2d');
30 | this.color = color;
31 | }
32 |
33 | shouldComponentUpdate(state, last){
34 | const g = state.layoutGrid;
35 | //this will be undefined the first time
36 | const pg = last.layoutGrid;
37 | return state.showDebugLayoutGrid !== last.showDebugLayoutGrid ||
38 | g !== pg ||
39 | g.column != pg.column || g.row !== pg.row ||
40 | state.innerWidth !== last.innerWidth ||
41 | state.innerHeight !== last.innerHeight;
42 | }
43 |
44 | render(state){
45 |
46 | this.ctx.lineWidth = 1;
47 | if(!this.domElement.parentElement){
48 | //inject it if its not in the active DOM
49 | document.body.appendChild(this.domElement);
50 | }
51 |
52 | if(!state.showDebugLayoutGrid){
53 | //if its in the dom, take it out
54 | this.domElement.parentElement && this.domElement.parentElement.removeChild(this.domElement);
55 | return;
56 | }
57 |
58 | Object.assign(this.domElement.style, {
59 | pointerEvents: 'none',
60 | zIndex: 10,
61 | position: 'fixed',
62 | top: 0,
63 | left: 0,
64 | boxSizing: 'border-box'
65 | });
66 |
67 | this.domElement.width = state.innerWidth;
68 | this.domElement.height = state.innerHeight;
69 | const grid = Object.assign({}, state.layoutGrid);
70 | grid.width = state.innerWidth;
71 | grid.height = state.innerHeight;
72 | const cells = grid2d.createCells(grid);
73 | this.ctx.clearRect(0, 0, this.domElement.width, this.domElement.height);
74 |
75 | this.ctx.strokeStyle = this.color;
76 | cells.forEach(cell=>
77 | this.ctx.strokeRect(cell.x, cell.y, cell.width, cell.height)
78 | );
79 |
80 | this.ctx.lineWidth = 2;
81 | Object.keys(state.layoutItems).forEach(key=>{
82 |
83 | const [a, b] = state.layoutItems[key];
84 |
85 | const tl = {
86 | x: grid2d.xForColumn(grid, a.column),
87 | y: grid2d.yForRow(grid, a.row)
88 | };
89 |
90 | const br = {
91 | x: grid2d.xForColumn(grid, b.column),
92 | y: grid2d.yForRow(grid, b.row)
93 | };
94 |
95 | this.ctx.beginPath();
96 | this.ctx.moveTo(tl.x, tl.y);
97 | this.ctx.lineTo(br.x, br.y);
98 | this.ctx.stroke();
99 |
100 | });
101 |
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/js/views/layout-containers.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import * as grid2d from 'grid2d';
16 | import { View } from './base-view';
17 | import { MOBILE_PORTRAIT } from '../models/responsive';
18 |
19 | /**
20 | * These layout containers are responsible for watching
21 | * the `state.layoutGrid` and adapting their dimensions to their item
22 | */
23 |
24 | const li = (s, l, item, i)=>
25 | s.layoutItems[item][i].column !== !l.layoutItems[item][i].column ||
26 | s.layoutItems[item][i].row !== l.layoutItems[item][i].row;
27 |
28 | const changed = (s, l, item)=>
29 | s.innerWidth !== l.innerWidth ||
30 | s.innerHeight !== l.innerHeight ||
31 | s.layoutItems && !l.layoutItems ||
32 | li(s, l, item, 0) ||
33 | li(s, l, item, 1);
34 |
35 |
36 | /**
37 | * GridContainer is the element containing the gradient grid (grid.js)
38 | * and 4 editable corners (tiles.js)
39 | */
40 | export class GridContainer extends View {
41 |
42 | constructor(domElement){
43 | super(domElement);
44 | }
45 |
46 | shouldComponentUpdate(state, last){
47 | return changed(state, last, 'gridContainer');
48 | }
49 |
50 | render(state){
51 |
52 | if(state.layout === MOBILE_PORTRAIT){
53 | Object.assign(this.domElement.style, {
54 | position: 'relative',
55 | top: 0,
56 | left: 0,
57 | width: '100%',
58 | height: 'auto'
59 | });
60 |
61 | return;
62 | }
63 |
64 | const cw = grid2d.cellWidth(state.layoutGrid);
65 | const ch = grid2d.cellHeight(state.layoutGrid);
66 | const li = state.layoutItems.gridContainer;
67 |
68 | const width = `${cw * (li[1].column - li[0].column) * state.innerWidth}px`;
69 |
70 | Object.assign(this.domElement.style, {
71 | position: 'absolute',
72 | left: `${cw * li[0].column * state.innerWidth}px`,
73 | top: `${ch * li[0].row * state.innerHeight}px`,
74 | width,
75 | height: width
76 | });
77 | }
78 | }
79 |
80 |
81 |
82 | /**
83 | * SequencerContainer is the container holding
84 | * the editable sequencer, the presets and the button
85 | */
86 | export class SequencerContainer extends View {
87 |
88 | constructor(domElement){
89 | super(domElement);
90 | }
91 |
92 | shouldComponentUpdate(state, last){
93 | return changed(state, last, 'sequencerContainer');
94 | }
95 |
96 | render(state){
97 |
98 | if(state.layout === MOBILE_PORTRAIT){
99 | Object.assign(this.domElement.style, {
100 | position: 'relative',
101 | top: 0,
102 | left: 0,
103 | width: '100%',
104 | height: `${state.innerHeight}px`
105 | });
106 |
107 | return;
108 | }
109 |
110 | const cw = grid2d.cellWidth(state.layoutGrid);
111 | const ch = grid2d.cellHeight(state.layoutGrid);
112 | const li = state.layoutItems.sequencerContainer;
113 |
114 | Object.assign(this.domElement.style, {
115 | position: 'absolute',
116 | left: `${cw * li[0].column * state.innerWidth}px`,
117 | top: `${ch * li[0].row * state.innerHeight}px`,
118 | width: `${cw * (li[1].column - li[0].column) * state.innerWidth}px`,
119 | height: `${ch * (li[1].row - li[0].row) * state.innerHeight}px`
120 | });
121 |
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/js/views/modal.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import { View } from './base-view';
16 | import * as modals from '../models/modals';
17 | import { copyToClipboard } from '../utils';
18 |
19 |
20 | const open = (url)=>
21 | window.open(url, 'fbShareWindow', 'height=450, width=550, top=' + (window.innerHeight / 2 - 275) + ', left=' + (window.innerWidth / 2 - 225) + ', toolbar=0, location=0, menubar=0, directories=0, scrollbars=0');
22 |
23 |
24 | const facebookId = '224976884733659';
25 | const description = 'Check out these beats I made using machine learning with Beat Blender';
26 | const twitterTxt = (url)=>`${description} → ${url} #beatblender`;
27 |
28 | const twitter = ({shareURL }) =>
29 | 'https://twitter.com/intent/tweet?text=' + window.encodeURIComponent(twitterTxt(shareURL));
30 |
31 | const base = 'https://experiments.withgoogle.com/ai/beat-blender/view/';
32 |
33 | const facebook = ({ shareURL }) =>
34 | [`https://www.facebook.com/dialog/feed?app_id=${facebookId}`,
35 | '&display=popup',
36 | `&link=${shareURL}`,
37 | '&name=Beat Blender',
38 | `&caption=${base}`,
39 | `&description=${description}`,
40 | `&picture=${base + 'assets/share.png'}?type=png`
41 | ].join('');
42 |
43 | // the html to repeat for every preset
44 | const shareTemplate = (state)=>`
45 |
46 |
47 |
Your beats are saved at this link:
48 |
49 |
COPY LINK
50 |
`;
55 |
56 | /**/
64 |
65 | const aboutTemplate = ()=>`
66 |
67 |
68 |
69 | VIDEO
70 |
71 |
72 | This experiment lets you explore and create beats in a fun new way using machine learning. Just drag the circle or draw a path to discover beats. It's built using a neural network trained on over 3.8 million drum beats.
73 | Using Deeplearn.js , the neural network runs locally in your web browser.
74 |
75 | Beat Blender was first presented at the 2017 NIPS conference. Built by Torin Blankensmith and Kyle Phillips from the Creative Lab and Adam Roberts from the Magenta team at Google using
76 | MusicVAE.js
77 | and
78 | Deeplearn.js . Get the open source code on Github here .
79 |
80 |
`;
81 |
82 | export class Modal extends View {
83 |
84 | constructor(domElement){
85 | super(domElement);
86 | this._setEventMap({
87 | 'click .share-facebook': (event, state)=> open(facebook(state)),
88 | 'click .share-twitter': (event, state)=> open(twitter(state)),
89 | 'click .exit': ()=> {
90 | this.domElement.classList.remove('active');
91 | setTimeout(() => { //call exit after fade time has elapsed
92 | this.emit('exit', this);
93 |
94 | const video = document.querySelector('.video > iframe');
95 | if(video) {
96 | //pause video on exit
97 | video.contentWindow.postMessage(JSON.stringify({ event: 'command', func: 'pauseVideo' }), '*');
98 | }
99 |
100 | }, 300);
101 | },
102 | 'click .copy-link': (event)=>{
103 | const input = document.querySelector('.short-url');
104 | copyToClipboard(input);
105 | event.target.innerHTML = 'COPIED';
106 | event.target.classList.add('copied');
107 | }
108 | });
109 | }
110 |
111 | shouldComponentUpdate(state, previousState) {
112 | return state.modal !== previousState.modal;
113 | }
114 |
115 | /**
116 | * render the provided presets
117 | * @param {Object} key becomes label, value (Array) is beats
118 | * @return itself
119 | */
120 | render(state, previousState) {
121 | this.domElement.style.visibility = previousState.modal === undefined ? 'hidden' : 'visible'; //on page load modal should be hidden
122 | if(state.modal === modals.ABOUT) {
123 | this.domElement.innerHTML = aboutTemplate(state);
124 | this.domElement.classList.add('active');
125 | } else if(state.modal === modals.SHARE) {
126 | this.domElement.innerHTML = shareTemplate(state);
127 | this.domElement.classList.add('active');
128 | } else {
129 | this.domElement.style.visibility = 'hidden';
130 | }
131 | return super.render(state, previousState);
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/js/views/preset-button-group.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import { View } from './base-view';
16 | import assert from 'assert';
17 |
18 | let isSafari = !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/) || /(CriOS)/i.test(navigator.userAgent);
19 |
20 |
21 | const same = (a, b)=>{
22 | if(!a || !b || a.length !== b.length){
23 | return false;
24 | }
25 | for(let i=0; i
36 | `PRESET BEATS
37 | ${button('Generate New Beat', `preset-button generate-new-beat-button ${isSafari? 'isSafari' : ''}`)}
38 | ${Object.keys(presetBeats).map(key=> button(key, 'preset-button ' + (same(encodedSequences[cornerIndices[selectedCornerIndex]], presetBeats[key]) ? 'active' : ''))).join('')}`;
39 |
40 | // the html to repeat for every preset
41 | const button = (text, classList)=>`
42 | ${text} `;
43 |
44 |
45 |
46 | export class PresetButtonGroup extends View {
47 |
48 | constructor(domElement){
49 | super(domElement);
50 |
51 | this._setEventMap({
52 | 'click .preset-button': (event, state)=>{
53 | if(event.target.classList.contains('generate-new-beat-button')) {
54 | this.emit('generate-new-beat', this);
55 | } else {
56 | const attr = event.target.attributes['data-value'];
57 | assert(attr && attr.value, 'Preset Button did not have a data-value attribute');
58 | const beat = state.presetBeats[attr.value];
59 | this.emit('click', this, attr.value, beat);
60 | }
61 | }
62 | });
63 | }
64 |
65 | shouldComponentUpdate(state, previousState) {
66 | const i = state.cornerIndices[state.selectedCornerIndex];
67 | return state.selectedCornerIndex !== previousState.selectedCornerIndex ||
68 | (!same(state.encodedSequences[i], previousState.encodedSequences[i]) && state.selectedCornerIndex > -1);
69 | }
70 |
71 | /**
72 | * render the provided presets
73 | * @param {Object} key becomes label, value (Array) is beats
74 | * @return itself
75 | */
76 | render(state, previousState){
77 | this.domElement.classList[state.selectedCornerIndex > -1 ? 'add' : 'remove']('active');
78 | this.domElement.innerHTML = template(state);
79 | return super.render(state, previousState);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/js/views/select-midi-out.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import { View } from './base-view';
16 |
17 | const DEFAULT_TEXT = 'Select Midi Out';
18 |
19 |
20 | const template = (text, isSelected)=> `
21 | ${text} `;
22 |
23 |
24 | export class SelectMidiOut extends View {
25 |
26 | constructor(domElement){
27 | super(domElement);
28 |
29 | this._setEventMap({
30 | 'change': (evt)=> this.emit('change', this, evt.target.selectedIndex -1) //-1 because of the default option
31 | });
32 | }
33 |
34 | shouldComponentUpdate({ midiOut }, { midiOut:lMidiOut }){
35 | //deep-equals cause it could be a clone
36 | if(midiOut && !lMidiOut){
37 | return true;
38 | }
39 | if(midiOut.length !== lMidiOut.length){
40 | return true;
41 | }
42 |
43 | for(let i=0; itemplate(device, i === state.selectedMidiOutIndex)))
56 | .join('');
57 |
58 | return super.render();
59 | }
60 |
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/js/views/sequence-player.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import Tone from 'tone';
16 | import { range } from '../utils';
17 | import { getMidiNoteFromDrumRow, urls as sampleURLs, getURLIndexForNote } from '../samples';
18 | import { View } from './base-view';
19 | import { sendMIDIToDevice } from '../midi-out';
20 | import { anyKeyNotEqual } from '../utils';
21 | import assert from 'assert';
22 |
23 |
24 | export class SequencePlayer extends View {
25 | constructor(){
26 | super(document.body);
27 |
28 | this.onEveryNote = this.onEveryNote.bind(this);
29 | this.onPlayerLoaded = this.onPlayerLoaded.bind(this);
30 |
31 | this.loop = new Tone.Sequence(this.onEveryNote, range(0, 32), '16n');
32 | this.notesOn = [];
33 | }
34 |
35 | onEveryNote(tickTime, col){
36 | if(!this.player.loaded){
37 | return;
38 | }
39 | this.emit('note', this, tickTime, col);
40 | }
41 |
42 | onPlayerLoaded(player){
43 | console.log(player);
44 | //setSequencerUINotes(mLSequencer.currNotes);
45 | Tone.Transport.start();
46 | console.log('Tone.Transport started');
47 | }
48 |
49 | shouldComponentUpdate(s, l){
50 | //first time or column changed
51 | return s.playing !== l.playing ||
52 | s.bpm !== l.bpm ||
53 | (!l.sequence && s.sequence) ||
54 | s.sequence.time !== l.sequence.time ||
55 | s.sequence.activeColumn !== l.sequence.activeColumn ||
56 | anyKeyNotEqual(s.activeNotes, l.activeNotes);
57 | }
58 |
59 | render(state, last){
60 | //load samples
61 | if(!this.player){
62 | assert(Array.isArray(sampleURLs), `sampleURLs should be an array, received ${sampleURLs}`);
63 | this.player = new Tone.Players(sampleURLs, this.onPlayerLoaded).toMaster();
64 | }
65 | //toggle play/pause
66 | if(state.playing && this.loop.state !== 'started'){
67 | this.loop.start();
68 | } else if(!state.playing && this.loop.state === 'started'){
69 | this.loop.stop();
70 | }
71 | //update bpm
72 | Tone.Transport.bpm.value = state.bpm;
73 |
74 | const notes = state.activeNotes;
75 |
76 | const midiDeviceName = state.midiOut[state.selectedMidiOutIndex];
77 | const channel = 10;
78 | const hasNotesOn = this.notesOn.length > 0 && notes.length > 0 || state.sequence.activeColumn == 1;
79 | if(midiDeviceName && hasNotesOn) {
80 | this.notesOn.forEach((midiNoteOn) => {
81 | sendMIDIToDevice(midiDeviceName, midiNoteOn, false, Math.random() * 0.5 + 0.5, channel);
82 | });
83 | this.notesOn = [];
84 | }
85 |
86 | for (let i = 0; i < notes.length; i++) {
87 | const vel = Math.random() * 0.5 + 0.5;
88 |
89 | let midiNote = getMidiNoteFromDrumRow(notes[i]);
90 |
91 | const midiDeviceName = state.midiOut[state.selectedMidiOutIndex];
92 | if(midiDeviceName && state.selectedMidiOutIndex >= 0) {
93 | sendMIDIToDevice(midiDeviceName, midiNote, true, vel, channel);
94 | this.notesOn.push(midiNote);
95 | } else {
96 | const player = this.player.get(getURLIndexForNote(midiNote));
97 | const time = state.sequence.time !== last.sequence.time ? state.sequence.time : Tone.Transport.now();
98 |
99 | player.start(time, 0, '2n', 0, vel);
100 | }
101 |
102 | }
103 | return this;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/js/views/sequencer-grid.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import * as grid2d from 'grid2d';
16 |
17 | import { View } from './base-view';
18 | import { dpr, setCanvasSize, renderGrid } from '../canvas-utils';
19 | import getMousePosition from '../get-mouse-position';
20 | import { notesToMatrix } from '../samples';
21 | import { times, lerpArray } from '../utils';
22 | import * as responsive from '../models/responsive';
23 |
24 |
25 | export class SequencerGridView extends View {
26 |
27 | constructor(domElement){
28 | super(domElement || document.createElement('canvas'));
29 |
30 | this.context = this.domElement.getContext('2d');
31 |
32 | let mouseDown = false;
33 | const pt = {};
34 | let lastIndex = -1;
35 |
36 |
37 | const onMouseDown = (event, { selectedCornerIndex, sequence })=>{
38 | mouseDown = true;
39 | //only toggle if the grid is in editable mode with a corner selected
40 | if(selectedCornerIndex < 0){
41 | return;
42 | }
43 |
44 | if(event.touches && event.touches.length){
45 | event.preventDefault();
46 | }
47 |
48 | const scaledGrid = grid2d.scale(sequence, this.domElement.clientWidth, this.domElement.clientHeight);
49 | getMousePosition(this.domElement, event, true, pt);
50 |
51 | const cellIndex = grid2d.closestCellIndex(scaledGrid, pt);
52 | if(cellIndex > -1){
53 | //flip it and make a boolean
54 | const pos = grid2d.cellPosition(scaledGrid, cellIndex);
55 | lastIndex = cellIndex;
56 | this.emit('toggle', this, pos, cellIndex);
57 | }
58 | };
59 |
60 | const onMouseLeave = () => {
61 | this.emit('mouseleave', this);
62 | };
63 |
64 | const onMouseMove = (event, { selectedCornerIndex, sequence })=>{
65 | //only toggle if the grid is in editable mode with a corner selected
66 | if(selectedCornerIndex < 0){
67 | return;
68 | }
69 |
70 | if(event.touches && event.touches.length){
71 | //touchstart might not get triggered first
72 | mouseDown = true;
73 | event.preventDefault();
74 | }
75 |
76 | const scaledGrid = grid2d.scale(sequence, this.domElement.clientWidth, this.domElement.clientHeight);
77 | getMousePosition(this.domElement, event, true, pt);
78 |
79 | const cellIndex = grid2d.intersectsCellIndex(scaledGrid, pt);
80 |
81 | if(cellIndex > -1){
82 | const pos = grid2d.cellPosition(scaledGrid, cellIndex);
83 | if(mouseDown){
84 | if(cellIndex !== lastIndex){
85 | this.emit('toggle', this, pos, cellIndex);
86 | lastIndex = cellIndex;
87 | }
88 | } else {
89 | //we are on a cell, mouse is not down and we don't care if it was the last one
90 | this.emit('hover', this, pos, cellIndex);
91 | }
92 | }
93 | };
94 |
95 |
96 | const onMouseUp = ()=> mouseDown = false;
97 |
98 |
99 | this._setEventMap({
100 | 'mouseover' : (event)=> event.target.title && (event.target.title = ''),
101 | //dont bind to both (it will get triggered twice), touch if available
102 | [window.ontouchstart ? 'touchstart' : 'mousedown'] : onMouseDown,
103 | 'mousemove' : onMouseMove,
104 | 'mouseleave' : onMouseLeave,
105 | 'mouseup' : onMouseUp,
106 | 'touchmove' : onMouseMove,
107 | 'touchend' : onMouseUp
108 | });
109 |
110 | }
111 |
112 | render(state, last){
113 |
114 | if(state.innerWidth !== last.innerWidth || state.innerHeight !== last.innerHeight){
115 | //resize
116 | const width = state.layout === responsive.MOBILE_PORTRAIT ? state.innerWidth : state.innerWidth * 0.5 * 0.8;
117 | setCanvasSize(this.domElement, width, width/2);
118 | }
119 |
120 | const c = this.context;
121 | const {
122 | sequence,
123 | encodedSequences,
124 | selectedIndex,
125 | selectedCornerIndex
126 | } = state;
127 |
128 | this.domElement.style.cursor = selectedCornerIndex >= 0 ? 'pointer' : 'inherit';
129 |
130 | c.clearRect(0, 0, c.canvas.width, c.canvas.height);
131 | const matrix = notesToMatrix(encodedSequences[selectedIndex], sequence.columns, sequence.rows);
132 |
133 | const { colorOn, colorOff } = sequence;
134 | /*
135 | const colorOn = sequence.selectedCornerIndex >= 0 ? state.gradient[sequence.selectedCornerIndex] : sequence.colorOn;
136 | const colorOff = sequence.colorOff;*/
137 |
138 | const colors = times(sequence.columns, (x)=>{
139 | let opacity = x === sequence.activeColumn ? 1 : (x/8 % 2 < 1) ? 0.33 : 0.2;
140 | if(selectedCornerIndex >= 0){
141 | opacity += 0.2;
142 | }
143 |
144 | return times(sequence.rows, (y)=> !!matrix[x][y] ?
145 | [colorOn[0], colorOn[1], colorOn[2], opacity] :
146 | [colorOff[0], colorOff[1], colorOff[2], opacity]
147 | );
148 | });
149 |
150 |
151 | const getColor = (x,y)=>{
152 | const hovCR = state.sequence.hoverCellPosition;
153 | const c = colors[x][y];
154 | if(hovCR && hovCR.column === x && hovCR.row === y){
155 | return lerpArray(c, colorOn, 0.25);
156 | //return [c[0], c[1], c[2], c[3] + 0.4];
157 | }
158 | return c;
159 | };
160 |
161 | renderGrid(c, sequence, getColor, c.canvas.width/dpr(), c.canvas.height/dpr(), ()=>true, v=>v);
162 |
163 | return this;
164 | }
165 | }
166 |
167 |
--------------------------------------------------------------------------------
/js/views/sequencer-label.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import { View } from './base-view';
16 | import { xForColumn, yForRow } from 'grid2d';
17 | import { MOBILE_PORTRAIT } from '../models/responsive';
18 |
19 |
20 |
21 | export class SequencerLabel extends View {
22 | constructor(domElement){
23 | super(domElement);
24 | }
25 |
26 | render(state){
27 | let label = '';
28 | /*const { width } = this.domElement.getBoundingClientRect();
29 | const height = ~~(cellHeight(state.grid) * width / 2);
30 | this.domElement.style.height = `${height}px`;*/
31 |
32 | const lg = state.layoutGrid;
33 | const [a, b] = state.layoutItems.sequencerLabel;
34 |
35 | if(!a || !b){
36 | return;
37 | }
38 |
39 | const x1 = xForColumn(lg, a.column);
40 | const x2 = xForColumn(lg, b.column);
41 | const y1 = yForRow(lg, a.row);
42 | const y2 = yForRow(lg, b.row);
43 |
44 | const height = `${(y2-y1) * state.innerHeight}px`;
45 |
46 | let css = (state.layout === MOBILE_PORTRAIT) ? ({
47 | position: 'relative',
48 | top: 0,
49 | left: 0,
50 | width: '100%',
51 | height
52 | }) : ({
53 | position: 'absolute',
54 | left: `${x1 * state.innerWidth}px`,
55 | top: `${y1 * state.innerHeight}px`,
56 | width: `${(x2-x1) * state.innerWidth}px`,
57 | height
58 | });
59 |
60 | Object.assign(this.domElement.style, css);
61 |
62 | if(state.selectedCornerIndex > -1){
63 | label = `Editing corner ${state.selectedCornerIndex + 1}`;
64 | } else {
65 | label = ''; //`Sampling column ${pos.column + 1}, row ${pos.row + 1}`;
66 | }
67 | this.domElement.innerHTML = label;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/js/views/spinner.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import { View } from './base-view';
16 |
17 |
18 | const template = ({ innerWidth, innerHeight })=>`
19 |
20 |
21 | `;
22 |
23 |
24 | export class Spinner extends View {
25 |
26 | constructor(domElement){
27 | super(domElement || document.createElement('div'));
28 | /*this.domElement.classList.add('modal');
29 | this.domElement.classList.add('active');*/
30 | document.body.appendChild(this.domElement);
31 | }
32 |
33 | shouldComponentUpdate(state, last){
34 | return state.loading !== last.loading || state.innerWidth !== last.innerWidth || state.innerHeight !== last.innerHeight;
35 | }
36 |
37 | render(state, last){
38 | this.domElement.innerHTML = state.loading ? template(state) : '';
39 | Object.assign(this.domElement.style, {
40 | display: state.loading ? 'block' : 'none',
41 | position: 'absolute',
42 | top: 0,
43 | left: 0,
44 | width: '100%',
45 | height: '100%',
46 | backgroundColor: 'rgba(0,0,0,0.7)'
47 | });
48 | return super.render(state, last);
49 | }
50 | }
51 |
52 |
--------------------------------------------------------------------------------
/js/views/tiles.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
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 | // https://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 | import { View } from './base-view';
17 | import { toCSSString } from '../models/color';
18 | import * as grid2d from 'grid2d';
19 | import { anyKeyNotEqual } from '../utils';
20 | import { MOBILE_PORTRAIT } from '../models/responsive';
21 |
22 |
23 | /**
24 | * recursively search the children elements for the child,
25 | * repeating the task on `parentElement`
26 | * @param {HTMLCollection} children
27 | * @param {HTMLElement} child
28 | * @return {Number} index of the child in the parentElement
29 | */
30 | const getChildIndex = (children, child)=>{
31 | if(!child){
32 | return -1;
33 | }
34 | for(let i=0; i{
45 | const foundCorners = this.cornerOrder.filter(corner => el.classList.contains(corner));
46 | if (foundCorners.length || depth > maxDepth) {
47 | return foundCorners[0];
48 | }
49 | return findIndexForInput(el.parentElement, depth++);
50 | };
51 |
52 |
53 | export class Corners extends View {
54 |
55 |
56 | constructor(domElement) {
57 | super(domElement);
58 | const el = this.domElement;
59 |
60 | this.cornerOrder = ['tl', 'tr', 'bl', 'br'];
61 |
62 | this._setEventMap({
63 | 'click': (event)=>{
64 | event.preventDefault();
65 | const i = getChildIndex(el.children, event.target);
66 | if(i > -1) {
67 | this.emit('click', this, i);
68 | }
69 | },
70 | 'mouseenter': (event)=> event.target.children[0].classList.add('edit'),
71 | 'mouseleave': (event)=> event.target.children[0].classList.remove('edit')
72 | });
73 | }
74 |
75 | shouldComponentUpdate(state, last){
76 | return anyKeyNotEqual(state, last, ['innerWidth', 'innerHeight', 'selectedCornerIndex']);
77 | }
78 |
79 | render(state){
80 |
81 | const cw = grid2d.cellWidth(state.layoutGrid);
82 | //const ch = grid2d.cellHeight(state.layoutGrid);
83 | const li = state.layoutItems.gridContainer;
84 |
85 | const tW = state.layout === MOBILE_PORTRAIT ? state.innerWidth : cw * (li[1].column - li[0].column) * state.innerWidth;
86 |
87 | const w = ~~(grid2d.cellWidth(state.grid) * tW);
88 |
89 | const calcBorder = (index)=>
90 | state.selectedCornerIndex === index ? '4px solid white' : 'none';
91 |
92 | this.domElement.style.display = (state.selectedCornerIndex === -1) ? 'none' : 'block';
93 |
94 | this.domElement.innerHTML = this.cornerOrder
95 | .map((corner, index)=>{
96 | const color = toCSSString(state.gradient[index]);
97 | const border = calcBorder(index);
98 | return `
99 |
100 |
${(index+1)}
101 |
102 |
`;
103 | })
104 | .join('');
105 | }
106 |
107 | }
108 |
109 |
--------------------------------------------------------------------------------
/json/preset-beats.json:
--------------------------------------------------------------------------------
1 | [{
2 | "Rock 1" : [1, 0, 1, 0, 2, 0, 0, 0, 1, 0, 1, 0, 2, 0, 0, 0, 1, 0, 1, 0, 2, 0, 0, 0, 1, 0, 1, 0, 2, 0, 0, 0],
3 | "Rock 2" : [385, 0, 1, 0, 256, 0, 1, 1, 386, 0, 0, 1, 256, 0, 1, 0, 385, 0, 1, 0, 256, 1, 0, 0, 386, 0, 1, 0, 258, 1, 1, 258],
4 | "Reggaeton" : [257, 0, 0, 258, 1, 0, 258, 0, 1, 256, 256, 2, 1, 0, 258, 0, 257, 0, 0, 258, 1, 0, 258, 0, 257, 256, 0, 258, 1, 0, 258, 0],
5 | "Break" : [5, 0, 5, 0, 6, 0, 4, 2, 5, 2, 5, 0, 6, 0, 4, 0, 5, 0, 5, 0, 6, 0, 4, 2, 5, 2, 5, 0, 6, 0, 4, 0],
6 | "Basic Backbeat" : [5, 0, 4, 0, 7, 0, 4, 0, 5, 0, 4, 0, 7, 0, 4, 0, 5, 0, 4, 0, 7, 0, 4, 0, 5, 0, 4, 0, 7, 0, 4, 0],
7 | "Boots & Cats" : [1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0],
8 | "Pop Punk" : [5, 4, 10, 5, 4, 5, 10, 4, 5, 4, 10, 5, 4, 5, 10, 4, 5, 4, 10, 5, 4, 5, 10, 4, 5, 5, 10, 5, 22, 26, 5, 6],
9 | "Half Time" : [5, 0, 4, 0, 4, 0, 5, 0, 6, 0, 4, 0, 4, 0, 5, 0, 4, 0, 5, 0, 4, 0, 5, 0, 6, 0, 4, 1, 4, 0, 5, 0],
10 | "Bossa Half Time" : [ 7, 0, 256, 0, 4, 0, 263, 0, 5, 0, 0, 0, 262, 0, 5, 0, 261, 0, 0, 0, 262, 0, 5, 0, 5, 0, 258, 0, 4, 0, 261, 0],
11 | "Samba Full Time" : [7, 256, 4, 263, 5, 0, 262, 5, 261, 0, 262, 5, 5, 258, 4, 261, 7, 256, 4, 263, 5, 0, 262, 5, 261, 0, 262, 5, 5, 258, 4, 261]
12 | },
13 | {
14 | "Arpegio" : [45, 0, 0, 0, 50, 0, 52, 0, 53, 0, 50, 0, 52, 0, 0, 0, 48, 0, 0, 0, 50, 0, 0, 0, 0, 0, 45, 0, 45, 0, 0, 0],
15 | "Numero Dueo" : [50, 53, 58, 53, 62, 58, 53, 50, 52, 55, 60, 55, 64, 60, 55, 52, 53, 57, 62, 57, 65, 62, 57, 53, 53, 57, 62, 62, 65, 69, 62, 69]
16 | }]
17 |
--------------------------------------------------------------------------------
/json/response.json:
--------------------------------------------------------------------------------
1 | [ [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0], [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0], [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0], [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0], [1,0,1,0,2,0,1,0,1,0,1,0,2,0,1,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0], [1,0,1,0,258,0,1,0,1,0,1,2,2,0,1,0,1,0,1,0,1,0,2,0,1,0,1,2,1,0,2,0], [257,0,0,0,258,0,1,0,1,0,256,2,1,0,2,0,257,0,0,0,1,0,258,0,257,0,256,2,1,0,2,0], [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,0,258,1,0,258,0,257,0,256,2,1,0,258,0], [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,0,258,1,0,258,0,257,256,0,258,1,0,258,0], [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,0,258,1,0,258,0,257,256,0,258,1,0,258,0], [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,0,258,1,0,258,0,257,256,0,258,1,0,258,0], [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0], [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0], [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0], [1,0,1,0,2,0,1,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0], [1,0,1,0,2,0,1,0,1,0,1,2,2,0,1,0,1,0,1,0,2,0,1,0,1,0,1,0,2,0,1,0], [257,0,256,0,258,0,1,0,1,0,1,2,0,0,1,0,1,0,1,0,258,0,1,0,257,0,256,2,1,0,2,0], [257,0,0,0,258,0,1,0,1,0,256,2,1,0,2,0,257,0,256,0,258,0,258,0,257,0,256,2,1,0,258,0], [257,0,0,258,1,0,258,0,1,0,256,2,1,0,258,0,257,0,256,258,1,0,258,0,257,256,0,258,1,0,258,0], [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,256,258,1,0,258,0,257,256,0,258,1,0,258,0], [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,0,258,1,0,258,0,257,256,0,258,1,0,258,0], [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,0,258,1,0,258,0,257,256,0,258,1,0,258,0], [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0], [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0], [1,0,1,0,2,0,1,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,1,0], [1,0,1,0,2,0,1,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,1,0,1,0,1,0,2,0,1,0], [257,0,256,0,258,0,1,0,1,0,1,2,0,0,0,0,1,0,1,0,2,0,1,0,1,0,1,2,1,0,2,0], [257,0,0,0,258,0,1,0,1,0,1,2,0,0,0,0,257,0,1,0,258,0,1,0,257,0,256,2,1,0,256,0], [257,0,0,0,258,0,1,0,1,0,1,2,1,0,0,0,257,0,256,0,258,0,258,0,257,256,0,258,1,0,258,0], [257,0,0,258,1,0,258,0,1,0,256,2,1,0,258,0,257,0,256,0,1,0,258,0,257,256,0,258,1,0,258,0], [257,0,0,258,1,0,258,0,1,0,256,2,1,0,258,0,257,0,256,258,1,258,258,0,257,256,0,258,1,0,258,0], [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,256,258,1,258,258,0,257,256,0,258,1,0,258,0], [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,258,258,1,258,258,0,257,256,256,258,1,0,258,0], [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0], [1,0,1,0,2,0,1,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,1,0], [1,0,1,0,2,0,1,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,2,2,0,0,0], [257,0,256,0,258,0,1,0,1,0,1,0,258,0,0,0,257,0,1,0,258,0,1,0,257,0,1,2,1,0,1,0], [257,0,0,0,258,0,1,0,1,0,1,2,0,0,0,0,257,0,1,0,258,0,1,0,257,0,1,2,1,0,256,0], [257,0,0,0,258,0,1,0,1,0,1,2,0,1,0,0,257,0,1,0,258,0,1,0,257,0,0,1,1,0,256,0], [257,0,0,258,1,0,258,0,1,0,1,2,1,0,0,0,257,0,1,258,0,1,258,0,257,256,0,258,1,0,258,0], [257,0,0,258,1,0,258,0,1,0,256,2,1,0,258,0,257,0,1,258,0,1,258,0,257,256,0,258,1,0,258,0], [257,0,0,258,1,0,258,0,1,0,256,2,1,0,258,0,257,0,258,258,0,258,258,0,257,256,0,258,1,0,258,0], [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,258,258,1,258,258,0,257,256,256,258,1,0,258,0], [257,0,0,258,1,0,258,0,1,256,0,258,1,0,258,0,257,0,258,258,1,258,258,0,257,256,256,258,1,0,258,256], [5,0,1,0,2,0,1,0,0,0,1,0,2,0,0,0,1,0,1,0,2,0,0,1,1,0,1,0,2,1,0,0], [257,0,1,0,2,0,1,0,0,0,1,0,258,0,0,0,1,0,1,0,2,0,0,1,1,0,1,0,2,1,0,0], [257,0,256,0,2,0,1,0,0,0,1,0,258,0,0,0,257,0,1,0,2,0,1,0,257,0,1,2,1,0,256,0], [257,0,0,0,258,0,1,0,0,0,1,0,258,0,0,0,257,0,1,0,258,0,1,0,257,0,1,2,1,0,256,0], [257,0,0,0,258,0,1,0,256,0,1,2,258,0,0,0,257,0,1,0,258,0,1,0,257,0,0,1,258,0,256,0], [257,0,0,258,0,1,0,0,1,0,1,2,0,1,0,0,257,0,1,0,258,0,1,0,257,256,0,1,258,0,256,0], [257,0,0,258,0,1,1,0,0,0,1,2,1,0,0,0,257,0,1,1,0,1,258,0,257,256,0,258,1,0,258,0], [257,0,0,258,0,1,1,0,0,0,1,2,1,0,258,0,257,0,1,258,0,1,258,0,257,256,0,258,1,0,258,256], [257,0,0,258,0,0,1,0,0,0,1,1,258,0,1,0,257,0,1,258,1,0,258,0,257,256,256,258,1,0,258,256], [257,0,0,258,0,0,1,0,0,256,1,2,1,0,258,0,257,0,258,1,1,258,258,0,257,256,256,258,1,0,258,256], [257,0,0,258,1,0,258,0,1,256,2,1,1,0,258,0,257,0,258,1,1,258,0,257,257,256,0,258,1,0,258,256], [5,0,0,0,6,0,1,0,0,0,5,0,1,0,0,0,1,0,1,0,2,0,0,1,0,0,1,2,2,1,0,0], [257,0,0,0,258,0,1,0,0,0,0,0,258,0,0,0,257,0,1,0,6,0,0,1,5,0,1,2,1,1,0,0], [257,0,0,0,258,0,1,0,0,0,1,0,258,0,0,0,257,0,1,0,258,0,0,0,257,0,1,2,1,0,256,0], [257,0,0,258,0,1,0,0,0,0,1,0,0,0,0,0,257,0,1,0,258,0,1,0,257,0,0,1,1,0,256,0], [257,0,0,258,0,1,0,0,0,0,1,1,258,0,0,0,257,0,1,1,0,0,1,0,257,1,0,2,1,0,8,0], [257,0,0,258,0,1,0,0,0,0,1,1,258,0,0,0,257,0,1,1,0,1,258,0,257,1,0,258,1,0,258,256], [257,0,0,258,0,1,1,0,0,0,1,1,258,0,0,0,257,0,1,1,0,1,258,0,257,256,0,258,1,0,258,256], [257,0,0,258,0,1,1,0,0,0,1,1,258,0,0,0,257,0,1,1,258,0,1,0,257,1,256,1,1,0,258,256], [257,0,0,258,0,1,1,0,0,0,1,1,258,0,0,0,257,0,258,1,1,0,258,0,257,1,256,258,1,0,258,256], [257,0,0,258,0,1,1,0,0,0,1,1,1,0,258,0,257,0,258,1,1,258,0,257,257,256,0,258,1,0,258,256], [257,0,0,258,0,1,1,0,0,0,1,1,1,0,258,0,257,0,258,1,1,258,0,257,257,256,256,1,1,0,258,256], [257,0,0,6,0,1,0,0,0,0,1,0,257,0,0,0,0,257,0,0,6,0,0,1,5,0,2,2,1,1,0,4], [257,0,0,258,0,1,0,0,0,0,1,0,257,0,0,0,0,257,1,0,6,0,0,1,257,0,2,1,2,1,0,0], [257,0,0,258,0,1,0,0,0,0,1,0,257,0,0,0,0,257,1,0,6,0,0,0,257,0,2,1,1,1,256,256], [257,0,0,258,0,1,0,0,0,0,1,1,257,0,0,0,257,0,1,0,258,0,1,0,257,1,0,1,1,1,256,256], [257,0,0,258,0,1,0,0,0,0,1,1,258,0,0,0,257,0,1,258,0,0,0,0,257,1,0,2,1,0,8,256], [257,0,0,258,0,1,257,0,0,258,1,1,257,0,0,0,257,0,1,258,0,1,258,0,257,1,0,258,1,0,258,256], [257,0,0,258,0,1,257,0,0,258,1,0,257,0,0,0,257,0,1,258,0,1,258,0,257,1,256,2,1,0,260,256], [257,0,0,258,0,1,1,0,0,258,1,1,258,0,0,0,257,0,258,1,1,0,258,1,257,257,256,2,1,0,260,256], [257,0,0,258,0,1,1,0,0,258,1,1,258,0,0,0,257,0,258,1,1,258,0,257,257,256,2,1,1,0,258,256], [257,0,0,258,0,1,1,0,0,0,1,1,258,0,256,0,257,0,258,1,1,258,0,257,1,257,256,1,1,0,260,257], [257,0,0,258,0,1,1,0,0,0,1,1,258,0,1,0,257,0,258,1,1,258,0,257,1,257,256,1,1,0,260,257], [5,0,0,6,0,1,0,0,0,0,6,0,257,0,0,0,0,257,5,0,0,0,0,257,257,0,2,2,1,257,0,256], [257,0,0,6,0,1,0,0,0,0,0,257,257,0,0,0,0,257,5,0,6,0,0,257,257,0,2,1,1,257,0,256], [257,0,0,6,0,1,0,0,0,0,0,257,257,0,0,0,0,257,1,0,6,0,256,257,257,0,6,1,1,257,256,256], [257,0,0,258,0,1,257,0,0,258,0,257,1,0,0,0,0,257,1,0,6,0,1,257,257,1,2,2,1,1,8,256], [257,0,0,258,0,1,257,0,0,258,0,257,1,0,0,0,0,257,1,0,6,0,1,257,257,0,0,1,1,1,256,256], [257,0,0,258,0,1,257,0,0,258,0,257,1,0,0,0,257,257,1,258,258,0,1,257,257,1,2,2,1,0,8,256], [257,0,0,258,0,1,257,0,0,258,0,257,1,0,0,0,257,257,0,258,1,0,258,257,257,1,2,256,1,0,260,256], [257,0,0,258,0,1,257,0,0,258,0,1,1,0,0,0,257,0,0,258,1,1,0,257,257,1,0,258,1,256,0,257], [257,0,0,258,0,1,257,0,0,258,0,0,1,258,258,0,257,0,1,258,1,1,0,257,1,257,256,1,1,0,260,257], [257,0,0,258,0,1,1,0,0,258,0,257,1,0,258,0,257,0,1,258,1,1,2,0,257,1,256,258,1,256,0,134], [257,0,0,258,0,1,1,0,0,258,1,1,258,0,0,0,257,0,258,1,1,1,2,272,257,1,256,264,1,256,256,134], [261,0,0,6,0,257,0,0,0,6,0,257,5,0,0,0,0,257,5,0,0,6,0,257,257,0,2,2,1,257,8,4], [257,0,0,6,0,257,5,0,0,6,0,257,257,0,0,6,0,257,5,0,0,6,0,257,257,0,2,2,1,257,8,4], [257,0,0,6,0,257,257,0,0,6,0,257,257,0,0,6,0,257,1,0,6,0,256,257,257,0,6,1,1,257,256,4], [257,0,0,6,0,1,257,0,0,6,0,257,1,0,0,6,0,257,1,0,6,0,1,257,0,1,2,2,1,1,8,256], [257,0,0,6,0,1,257,0,0,6,0,257,1,0,0,258,0,257,1,0,6,0,0,257,257,0,2,1,1,257,256,256], [257,0,0,258,0,1,257,0,0,258,0,257,1,0,0,0,0,257,1,258,258,0,1,257,257,257,2,6,1,256,8,256], [257,0,0,258,0,1,257,0,0,258,0,257,1,0,258,0,1,257,0,258,1,256,0,257,1,257,0,258,1,256,256,257], [257,0,0,258,0,1,257,0,0,258,0,257,1,0,258,0,1,257,0,258,1,256,0,257,1,257,2,1,1,256,256,257], [257,0,0,258,0,256,257,0,0,258,0,257,1,0,258,0,1,257,0,258,1,1,1,0,257,1,256,264,1,256,4,134], [257,0,0,2,0,256,1,0,0,258,0,257,1,0,258,0,1,257,1,258,1,64,1,272,1,257,8,258,1,256,256,134], [257,0,0,2,0,256,1,0,0,258,0,257,1,0,258,0,1,257,1,258,1,64,1,272,1,257,8,264,1,256,4,389], [261,0,0,6,0,257,5,0,0,6,0,257,5,0,0,6,0,257,5,0,0,6,0,257,5,0,2,6,1,257,8,4], [261,0,0,6,0,257,5,0,0,6,0,257,5,0,0,6,0,257,5,0,0,6,0,257,257,0,6,2,1,257,8,4], [261,0,0,6,0,257,5,0,0,6,0,257,257,0,0,6,0,257,5,0,6,0,256,257,0,1,6,2,1,5,8,4], [257,0,0,6,0,257,257,0,0,6,0,257,257,0,0,6,0,257,1,0,6,0,1,257,0,5,2,256,1,1,8,256], [257,0,0,6,0,257,257,0,0,6,0,257,257,0,0,258,0,257,1,0,6,256,0,257,257,0,6,1,1,257,4,8], [257,0,0,6,0,1,257,0,0,6,0,257,1,0,0,258,0,257,1,258,0,256,1,257,257,1,6,1,257,256,8,260], [257,0,0,258,0,256,257,0,0,2,0,257,1,0,258,0,1,257,0,258,1,256,0,257,1,258,0,5,1,8,4,257], [257,0,0,2,0,256,257,0,0,2,0,257,1,0,258,0,1,257,1,258,1,256,0,257,1,257,2,260,1,256,4,261], [257,0,0,2,0,256,257,0,0,2,0,257,1,0,258,0,1,257,1,258,1,64,1,257,1,257,8,260,1,256,4,261], [257,0,0,2,0,256,257,0,0,2,0,257,1,0,258,0,1,257,1,258,1,64,1,16,1,257,8,264,1,256,4,389], [257,0,0,2,0,256,1,0,0,2,0,257,1,0,258,0,1,257,1,258,1,64,16,272,1,257,8,264,1,256,4,389], [261,0,0,6,0,257,5,0,0,6,0,257,5,0,0,6,0,257,5,0,0,6,0,257,5,0,2,6,1,257,8,4], [261,0,0,6,0,257,5,0,0,6,0,257,5,0,0,6,0,257,5,0,6,6,0,257,5,0,2,6,1,257,8,4], [261,0,0,6,0,257,5,0,0,6,0,257,5,0,0,6,0,257,5,0,6,0,256,257,0,1,6,2,5,1,8,4], [257,0,0,6,0,257,257,0,0,6,0,257,257,0,0,6,0,257,1,0,6,0,1,257,0,0,2,1,5,1,256,260], [257,0,0,6,0,257,257,0,0,6,0,257,257,0,0,6,0,257,1,0,6,256,1,257,257,2,6,1,1,5,256,260], [257,0,0,6,0,257,257,0,0,6,0,257,257,0,0,258,0,257,1,258,0,6,1,257,257,1,2,8,257,256,256,260], [257,0,0,6,0,256,257,0,0,2,0,257,1,0,258,0,1,257,1,258,6,256,1,257,16,257,2,260,1,256,256,261], [257,0,0,2,0,256,257,0,0,2,0,257,1,0,258,0,1,257,1,258,1,256,1,257,16,257,2,260,1,256,4,261], [257,0,0,2,0,256,257,0,0,2,0,257,1,0,258,0,1,257,1,258,1,64,1,16,1,257,8,264,1,256,4,261], [257,0,0,2,0,256,257,0,0,2,0,257,1,0,258,0,1,257,1,258,1,64,16,16,1,257,8,264,1,4,256,389], [257,0,0,2,0,256,257,0,0,2,0,257,1,0,258,0,1,257,1,258,1,64,16,16,1,257,8,264,1,4,4,389]]
2 |
--------------------------------------------------------------------------------
/json/response3.json:
--------------------------------------------------------------------------------
1 | [[1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,4,0],
2 | [1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,4,0],
3 | [1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,4,0],
4 | [1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,0,0,0,0,1,0,0,0,1,0,4,0],
5 | [1,0,4,0,1,0,5,0,5,0,4,0,1,0,5,0,1,0,4,0,0,0,0,0,5,0,0,0,1,0,5,0],
6 | [1,0,4,0,4,0,5,0,5,0,4,0,130,0,5,0,5,0,4,0,2,0,0,0,5,0,1,0,20,0,5,0],
7 | [6,0,4,0,4,0,133,0,5,0,4,0,130,0,5,0,5,0,4,0,2,0,0,0,5,0,2,0,20,0,5,0],
8 | [6,0,4,0,4,0,133,0,5,0,4,0,22,0,5,0,5,0,4,0,22,0,4,0,5,0,20,0,20,0,5,0],
9 | [6,0,4,0,4,0,23,0,5,0,4,0,22,0,5,0,5,0,4,0,22,0,5,0,5,0,22,0,20,0,21,0],
10 | [6,0,4,0,4,0,23,0,5,0,4,0,22,0,13,0,5,0,4,0,22,0,5,0,5,0,22,0,20,0,21,0],
11 | [6,0,4,0,4,0,23,0,5,0,4,0,22,0,13,0,5,0,4,0,22,0,5,0,5,0,22,0,20,0,21,0],
12 | [1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,4,0],
13 | [1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,4,0],
14 | [1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,4,0],
15 | [1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,0,0,0,0,1,0,0,0,1,0,4,0],
16 | [1,0,4,0,1,0,5,0,5,0,4,0,130,0,4,0,5,0,0,0,2,0,0,0,5,0,0,0,1,0,4,0],
17 | [1,0,4,0,4,0,5,0,5,0,4,0,130,0,5,0,5,0,0,0,6,0,0,0,5,0,0,0,5,0,5,0],
18 | [6,0,4,0,4,0,133,0,5,0,4,0,10,0,5,0,5,0,4,0,6,0,0,0,5,0,16,0,20,0,5,0],
19 | [6,0,4,0,4,0,133,0,5,0,4,0,22,0,5,0,5,0,4,0,6,0,5,0,5,0,20,0,20,0,5,0],
20 | [6,0,4,0,4,0,21,0,5,0,4,0,22,0,5,0,5,0,4,0,22,0,5,0,5,0,20,0,20,0,5,0],
21 | [6,0,4,0,4,0,23,0,5,0,4,0,22,0,5,0,5,0,4,0,22,0,5,0,5,0,22,0,20,0,21,0],
22 | [6,0,4,0,4,0,23,0,5,0,4,0,22,0,13,0,5,0,4,0,22,0,5,0,5,0,22,0,20,0,21,0],
23 | [1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,4,0],
24 | [1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,4,0],
25 | [1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,4,0],
26 | [1,0,4,0,1,0,5,0,1,0,4,0,1,0,4,0,1,0,4,0,0,0,0,0,5,0,0,0,1,0,4,0],
27 | [1,0,4,0,1,0,5,0,5,0,4,0,130,0,4,0,5,0,0,0,6,0,0,0,5,0,0,0,5,0,4,0],
28 | [5,0,4,0,4,0,5,0,5,0,4,0,10,0,5,0,5,0,0,0,6,0,0,0,5,0,0,0,20,0,5,0],
29 | [6,0,4,0,4,0,133,0,5,0,4,0,10,0,5,0,5,0,0,0,6,0,0,0,5,0,16,0,20,0,5,0],
30 | [6,0,4,0,4,0,133,0,5,0,4,0,22,0,5,0,5,0,0,0,6,0,5,0,5,0,16,0,20,0,5,0],
31 | [6,0,4,0,4,0,133,0,5,0,4,0,22,0,5,0,5,0,0,0,22,0,5,0,5,0,20,0,20,0,5,0],
32 | [6,0,4,0,4,0,23,0,5,0,4,0,22,0,5,0,5,0,4,0,22,0,5,0,5,0,20,0,20,0,5,0],
33 | [6,0,4,0,4,0,23,0,5,0,4,0,22,0,5,0,5,0,4,0,22,0,5,0,5,0,22,0,20,0,21,0],
34 | [1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,1,0,4,0,0,0,0,0,1,0,0,0,1,0,4,0],
35 | [1,0,4,0,1,0,5,0,1,0,4,0,1,0,4,0,1,0,4,0,0,0,0,0,1,0,0,0,1,0,4,0],
36 | [1,0,4,0,1,0,5,0,1,0,4,0,1,0,4,0,1,0,4,0,0,0,0,0,5,0,0,0,1,0,4,0],
37 | [1,0,4,0,1,0,5,0,5,0,4,0,10,0,4,0,1,0,0,0,0,0,0,0,5,0,0,0,1,0,4,0],
38 | [5,0,4,0,4,0,5,0,5,0,4,0,10,0,4,0,5,0,0,0,6,0,0,0,5,0,0,0,5,0,4,0],
39 | [5,0,4,0,4,0,5,0,5,0,4,0,10,0,5,0,5,0,0,0,6,0,0,0,5,0,0,0,20,0,5,0],
40 | [6,0,4,0,4,0,129,0,5,0,4,0,10,0,5,0,5,0,0,0,6,0,5,0,5,0,0,0,20,0,5,0],
41 | [6,0,0,0,4,0,133,0,4,0,0,0,70,0,5,0,5,0,0,0,6,0,5,0,5,0,0,0,20,0,5,0],
42 | [6,0,0,4,0,0,133,0,4,0,0,0,70,0,20,0,5,0,0,0,6,0,5,0,5,0,0,0,20,0,5,0],
43 | [6,0,0,0,4,0,133,0,4,0,0,0,70,0,20,0,5,0,0,0,22,0,5,0,5,0,20,0,20,0,5,0],
44 | [6,0,0,0,4,0,133,0,4,0,0,0,70,0,9,0,4,0,0,0,22,0,5,0,5,0,20,0,20,0,5,0],
45 | [5,0,4,0,5,0,5,0,5,0,4,0,3,0,4,0,1,0,4,0,0,0,0,0,9,0,0,0,1,0,4,0],
46 | [5,0,4,0,68,0,5,0,5,0,4,0,10,0,4,0,1,0,4,0,0,0,0,0,9,0,0,0,1,0,4,0],
47 | [5,0,4,0,68,0,5,0,5,0,4,0,10,0,4,0,1,0,4,0,0,0,0,0,5,0,0,0,5,0,4,0],
48 | [5,0,4,0,68,0,5,0,5,0,4,0,10,0,4,0,5,0,0,0,68,0,0,0,5,0,0,0,5,0,4,0],
49 | [5,0,4,0,4,0,5,0,5,0,4,0,10,0,4,0,5,0,0,0,68,0,0,0,5,0,0,0,5,0,4,0],
50 | [5,0,4,0,4,0,9,0,5,0,4,0,66,0,4,0,5,0,0,0,68,0,0,0,5,0,0,0,20,0,4,0],
51 | [6,0,0,4,4,0,129,0,5,0,0,0,10,0,20,0,5,0,0,0,68,0,1,0,5,0,0,0,20,0,5,0],
52 | [6,0,0,4,4,0,129,0,5,0,0,0,10,0,20,0,5,0,0,0,68,0,1,0,5,0,0,0,20,0,5,0],
53 | [6,0,0,0,4,0,129,0,4,0,0,0,10,0,20,0,5,0,0,0,6,0,5,0,5,0,0,0,20,0,5,0],
54 | [6,0,0,0,4,0,129,0,4,0,0,0,10,0,20,0,5,0,0,0,20,0,1,0,5,0,0,0,20,0,5,0],
55 | [6,0,0,0,4,0,129,0,0,0,4,0,0,0,9,0,4,0,0,0,20,0,1,0,5,0,0,0,20,0,5,0],
56 | [5,0,4,0,68,0,5,0,5,0,4,0,7,0,100,0,129,0,4,0,4,0,0,0,9,0,4,0,5,0,4,0],
57 | [5,0,4,0,68,0,5,0,5,0,4,0,7,0,100,0,129,0,4,0,4,0,0,0,9,0,0,0,5,0,4,0],
58 | [5,0,4,0,68,0,5,0,5,0,4,0,10,0,4,0,129,0,4,0,4,0,0,0,5,0,0,0,5,0,4,0],
59 | [5,0,4,0,68,0,5,0,5,0,4,0,10,0,4,0,129,0,4,0,68,0,0,0,5,0,0,0,5,0,4,0],
60 | [5,0,4,0,68,0,5,0,5,0,4,0,10,0,4,0,5,0,0,0,68,0,0,0,5,0,0,0,20,0,4,0],
61 | [5,0,0,4,4,0,16,0,5,0,0,0,66,0,4,0,5,0,0,0,68,0,0,0,5,0,0,0,20,0,4,0],
62 | [6,0,0,4,4,0,16,0,5,0,0,0,10,0,64,0,5,0,0,0,68,0,1,0,5,0,0,0,20,0,0,0],
63 | [6,0,0,0,4,0,129,0,4,0,0,0,10,0,64,0,5,0,0,0,68,0,1,0,5,0,0,0,20,0,0,0],
64 | [6,0,0,0,4,0,16,0,0,0,4,0,0,0,0,0,5,0,0,0,68,0,1,0,5,0,0,0,20,0,0,0],
65 | [0,0,4,0,0,0,20,0,0,0,4,0,0,0,5,0,0,0,0,0,20,0,1,0,0,0,0,0,20,0,0,0],
66 | [0,0,4,0,0,0,20,0,0,0,0,0,20,0,0,0,5,0,0,0,68,0,1,0,0,0,0,0,20,0,0,0],
67 | [5,0,4,4,68,0,5,0,13,0,4,0,7,0,100,0,129,0,4,0,4,0,7,0,9,0,4,0,7,0,4,0],
68 | [5,0,4,0,68,0,5,0,5,0,4,0,7,0,100,0,129,0,4,0,4,0,7,0,9,0,0,0,5,0,4,0],
69 | [5,0,4,0,68,0,5,0,5,0,4,0,7,0,100,0,129,0,4,0,68,0,5,0,5,0,0,0,5,0,4,0],
70 | [5,0,4,0,68,0,5,0,5,0,4,0,70,0,64,0,5,0,0,0,68,0,0,0,5,0,0,0,20,0,4,0],
71 | [5,0,0,4,68,0,20,0,5,0,0,0,70,0,64,0,5,0,0,0,68,0,0,0,5,0,0,0,20,0,4,0],
72 | [5,0,0,4,64,0,20,0,5,0,0,0,66,0,4,0,5,0,0,0,68,0,0,0,5,0,0,0,20,0,0,0],
73 | [6,0,0,0,68,0,16,0,5,0,0,0,68,0,64,0,5,0,0,0,68,0,0,0,5,0,0,0,20,0,0,0],
74 | [0,0,4,0,64,0,20,0,0,0,4,0,0,0,0,0,5,0,0,0,68,0,0,0,5,0,0,0,20,0,0,0],
75 | [0,0,0,0,64,0,20,0,0,0,0,0,0,0,0,0,5,0,0,0,68,0,0,0,5,0,0,0,20,0,0,0],
76 | [0,0,0,0,64,0,16,0,0,0,0,0,0,0,0,0,5,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0],
77 | [0,0,0,0,64,0,16,0,0,0,0,0,64,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0],
78 | [15,0,4,4,68,0,7,0,13,0,100,0,7,32,100,0,143,0,4,0,68,0,7,0,13,0,4,0,7,0,36,0],
79 | [7,0,4,0,68,0,21,0,5,0,4,0,7,0,100,0,129,0,4,0,68,0,7,0,5,0,4,0,7,0,4,0],
80 | [7,0,4,0,68,0,7,0,5,0,4,0,7,0,100,0,129,0,4,0,68,0,7,0,5,0,0,0,7,0,4,0],
81 | [7,0,4,0,68,0,20,0,5,0,0,0,70,0,64,0,129,0,0,4,68,0,0,0,5,0,0,0,20,0,4,0],
82 | [5,0,0,4,68,0,20,0,5,0,0,0,70,0,64,0,5,0,0,4,68,0,0,0,5,0,0,0,20,0,0,0],
83 | [5,0,0,4,68,0,16,0,5,0,0,0,70,0,64,0,5,0,0,0,68,0,0,0,5,0,0,0,20,0,0,0],
84 | [0,0,0,0,68,0,16,0,0,0,0,0,20,0,64,0,0,0,0,0,68,0,0,0,5,0,0,0,20,0,0,0],
85 | [0,0,0,0,64,0,16,0,0,0,0,0,20,0,0,0,5,0,0,0,68,0,0,0,5,0,0,0,0,0,0,0],
86 | [0,0,0,0,64,0,16,0,0,0,0,0,64,0,0,0,5,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0],
87 | [0,0,0,0,64,0,16,0,0,0,0,0,64,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0],
88 | [0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0],
89 | [15,0,4,4,68,0,23,0,13,0,100,0,7,32,52,0,143,0,4,4,68,0,23,0,13,0,4,0,7,0,36,0],
90 | [15,0,4,4,68,0,23,0,5,0,100,0,7,32,100,0,143,0,4,0,68,0,23,0,13,0,4,0,7,0,36,0],
91 | [7,0,4,0,68,0,21,0,5,0,4,0,103,0,100,0,129,0,4,0,68,0,7,0,5,0,0,0,7,0,36,0],
92 | [7,0,4,0,68,0,133,0,5,0,0,0,70,0,64,0,129,0,0,4,68,0,0,0,5,0,0,0,20,0,0,0],
93 | [7,0,0,4,68,0,16,0,5,0,0,0,70,0,64,0,129,0,0,4,68,0,0,0,5,0,0,0,20,0,0,0],
94 | [5,0,0,4,68,0,16,0,5,0,0,0,68,0,64,0,0,0,0,0,68,0,16,0,5,0,0,0,20,0,0,0],
95 | [0,0,0,0,68,0,16,0,0,0,0,0,68,0,0,0,132,0,0,0,68,0,16,0,0,0,0,0,0,0,0,0],
96 | [0,0,0,0,64,0,16,0,0,0,0,0,64,0,0,0,132,0,0,0,68,0,0,0,0,0,0,0,0,0,0,0],
97 | [0,0,0,0,64,0,16,0,0,0,0,0,64,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0],
98 | [0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0],
99 | [0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0],
100 | [15,0,4,4,68,0,23,0,13,0,100,0,39,32,52,0,143,0,4,4,68,0,23,0,13,0,100,0,7,0,36,0],
101 | [15,0,4,4,68,0,23,0,13,0,100,0,103,32,52,0,143,0,4,4,68,0,23,0,13,0,4,0,7,0,36,0],
102 | [15,0,4,0,68,0,23,0,5,0,4,0,103,0,100,0,141,0,4,0,68,0,23,0,13,0,4,0,7,0,36,0],
103 | [7,0,0,4,68,0,131,0,5,0,0,0,103,0,52,0,129,0,4,4,68,0,131,0,5,0,0,0,7,0,32,0],
104 | [7,0,0,4,68,0,16,0,5,0,0,0,70,0,32,0,129,0,0,4,68,0,0,0,5,0,0,0,20,0,0,0],
105 | [207,0,0,4,68,0,16,0,5,0,0,0,101,0,32,0,0,0,0,0,68,0,16,0,5,0,0,0,20,0,0,0],
106 | [0,0,0,0,68,0,16,0,0,0,0,0,68,0,0,0,132,0,0,0,68,0,16,0,0,0,0,0,0,0,0,0],
107 | [0,0,0,0,64,0,16,0,0,0,0,0,64,0,0,0,0,0,0,0,68,0,0,0,0,0,0,0,0,0,0,0],
108 | [0,0,0,0,64,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0],
109 | [0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0],
110 | [0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0],
111 | [15,0,4,4,68,0,23,0,13,0,100,0,39,32,52,0,143,0,4,4,68,0,23,0,13,0,100,0,7,0,36,0],
112 | [15,0,4,4,68,0,23,0,13,0,100,0,39,32,52,0,143,0,4,4,68,0,23,0,13,0,100,0,7,0,36,0],
113 | [15,0,4,0,68,0,23,0,13,0,100,0,103,0,52,0,143,0,4,4,68,0,23,0,13,0,4,0,7,0,36,0],
114 | [7,0,0,4,68,0,23,0,5,0,0,0,103,0,52,0,141,0,0,4,68,0,23,0,5,0,0,0,7,0,32,0],
115 | [7,0,0,4,68,0,16,0,5,0,0,0,103,0,32,0,129,0,0,4,68,0,131,0,5,0,0,0,68,0,0,0],
116 | [207,0,0,0,68,0,16,0,0,0,0,0,101,0,32,0,0,0,0,0,68,0,16,0,5,0,0,0,20,0,0,0],
117 | [0,0,0,0,68,0,16,0,0,0,0,0,68,0,0,0,128,0,0,0,68,0,16,0,0,0,0,0,0,0,0,0],
118 | [0,0,0,0,64,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,68,0,0,0,0,0,0,0,0,0,0,0],
119 | [0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0],
120 | [0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0],
121 | [0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0]]
122 |
--------------------------------------------------------------------------------
/json/response4.json:
--------------------------------------------------------------------------------
1 | [[1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
2 | [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
3 | [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
4 | [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
5 | [1,0,1,0,2,0,1,0,1,0,1,0,2,0,1,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
6 | [1,0,1,0,258,0,1,0,1,0,1,2,2,0,1,0,1,0,1,0,1,0,2,0,1,0,1,2,1,0,2,0],
7 | [257,0,0,0,258,0,1,0,1,0,256,2,1,0,2,0,257,0,0,0,1,0,258,0,257,0,256,2,1,0,2,0],
8 | [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,0,258,1,0,258,0,257,0,256,2,1,0,258,0],
9 | [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,0,258,1,0,258,0,257,256,0,258,1,0,258,0],
10 | [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,0,258,1,0,258,0,257,256,0,258,1,0,258,0],
11 | [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,0,258,1,0,258,0,257,256,0,258,1,0,258,0],
12 | [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
13 | [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
14 | [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
15 | [1,0,1,0,2,0,1,0,1,0,1,0,2,0,1,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
16 | [1,0,1,0,2,0,1,0,1,0,1,2,2,0,1,0,1,0,1,0,2,0,1,0,1,0,1,0,2,0,2,0],
17 | [1,0,1,0,258,0,1,0,1,0,1,2,2,0,1,0,1,0,1,0,258,0,1,0,257,0,1,2,1,0,2,0],
18 | [257,0,256,0,258,0,1,0,1,0,1,2,1,0,2,0,257,0,256,0,258,0,258,0,257,0,256,2,1,0,258,0],
19 | [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,256,0,1,0,258,0,257,256,0,258,1,0,258,0],
20 | [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,256,258,1,0,258,0,257,256,0,258,1,0,258,0],
21 | [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,0,258,1,0,258,0,257,256,0,258,1,0,258,0],
22 | [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,0,258,1,0,258,0,257,256,0,258,1,0,258,0],
23 | [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
24 | [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
25 | [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
26 | [1,0,1,0,2,0,1,0,1,0,1,0,2,0,1,0,1,0,1,0,2,0,1,0,1,0,1,0,2,0,0,0],
27 | [1,0,1,0,2,0,1,0,1,0,1,2,2,0,1,0,1,0,1,0,2,0,1,0,1,0,1,2,2,0,0,0],
28 | [257,0,256,0,258,0,1,0,1,0,1,2,2,0,1,0,257,0,1,0,258,0,1,0,257,0,1,2,258,0,256,0],
29 | [257,0,256,0,258,0,1,0,1,0,1,2,1,0,2,0,257,0,1,0,258,0,1,0,257,256,0,1,258,0,256,0],
30 | [257,0,0,258,1,0,258,0,1,0,256,2,1,0,258,0,257,0,256,0,1,0,258,0,257,256,0,258,1,0,258,0],
31 | [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,256,258,1,258,258,0,257,256,0,258,1,0,258,0],
32 | [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,256,258,1,258,258,0,257,256,0,258,1,0,258,0],
33 | [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,258,258,1,258,258,0,257,256,256,258,1,0,258,0],
34 | [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
35 | [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
36 | [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
37 | [1,0,1,0,2,0,256,0,1,0,1,2,2,0,0,0,1,0,1,0,2,0,1,0,1,0,1,1,2,0,0,0],
38 | [257,0,1,0,258,0,256,0,1,0,1,2,1,0,2,0,257,0,1,0,258,0,256,0,257,0,1,2,258,0,256,0],
39 | [257,0,256,0,258,0,1,0,1,0,1,2,2,0,256,0,257,0,1,0,258,0,1,0,257,256,1,1,258,0,256,0],
40 | [257,0,256,0,258,0,1,0,1,0,1,1,2,0,1,0,257,0,1,0,258,0,1,0,257,256,1,1,258,0,256,0],
41 | [257,0,0,258,1,0,258,0,1,0,256,2,1,0,258,0,257,0,258,0,1,258,258,0,257,256,0,258,1,0,258,0],
42 | [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,258,1,1,258,258,0,257,256,256,258,1,0,258,0],
43 | [257,0,0,258,1,0,258,0,1,256,256,2,1,0,258,0,257,0,258,258,1,258,258,0,257,256,256,258,1,0,258,0],
44 | [257,0,0,258,1,0,258,0,1,256,0,258,1,0,258,0,257,0,258,258,1,258,258,0,257,256,256,258,1,0,258,256],
45 | [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
46 | [1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0,1,0,1,0,2,0,0,0],
47 | [257,0,1,0,258,0,256,0,1,0,1,1,2,0,256,0,257,0,1,0,258,0,256,0,1,0,1,0,258,0,256,0],
48 | [257,0,1,0,258,0,256,0,1,0,1,1,2,0,256,0,257,0,1,0,258,0,256,0,257,0,1,1,258,0,256,0],
49 | [257,0,1,0,258,0,256,0,1,0,1,1,2,0,256,0,257,0,1,0,258,0,256,0,257,2,1,1,258,0,256,0],
50 | [257,0,256,0,258,0,256,0,1,0,1,1,2,0,256,0,257,0,1,0,258,0,1,0,257,256,1,1,258,0,256,0],
51 | [257,0,256,0,258,0,1,0,1,0,1,1,2,0,256,0,257,0,258,1,1,0,258,0,257,256,1,1,258,0,256,0],
52 | [257,0,0,258,1,0,258,0,1,0,1,2,1,0,258,0,257,0,258,1,0,1,258,0,257,256,256,1,1,0,258,0],
53 | [257,0,0,258,1,0,258,0,1,0,2,1,1,0,258,0,257,0,258,1,1,0,258,0,257,256,256,258,1,0,258,0],
54 | [257,0,0,258,1,0,258,0,1,0,2,1,1,0,258,0,257,0,258,1,1,258,258,0,257,256,256,258,1,0,258,256],
55 | [257,0,0,258,1,0,258,0,1,256,2,1,1,0,258,0,257,0,258,1,1,258,0,257,257,256,0,258,1,0,258,256],
56 | [257,0,1,0,258,0,256,0,1,2,1,0,258,0,256,0,257,0,1,0,2,0,256,0,2,0,257,0,258,0,256,0],
57 | [257,0,1,0,258,0,256,0,1,2,1,0,258,0,256,0,257,0,1,0,258,0,256,0,1,2,1,0,258,0,256,0],
58 | [257,0,1,0,258,0,256,0,1,2,1,0,258,0,256,0,257,0,1,0,258,0,256,0,1,2,1,0,258,0,256,0],
59 | [257,0,1,0,258,0,256,0,1,2,1,1,258,0,256,0,257,0,1,0,258,0,256,0,257,2,1,1,258,0,256,0],
60 | [257,0,1,0,258,0,256,0,1,2,1,1,258,0,256,0,257,0,1,0,258,0,256,0,257,2,1,1,258,0,256,0],
61 | [257,0,256,0,258,0,256,0,1,0,1,1,258,0,256,0,257,0,1,2,258,0,256,0,257,1,1,1,258,0,256,0],
62 | [257,0,256,0,258,0,1,0,256,0,1,1,258,0,256,0,257,0,258,1,0,0,258,0,257,1,256,1,258,0,256,0],
63 | [257,0,0,258,0,0,1,0,0,0,1,1,258,0,256,0,257,0,258,1,1,0,258,256,257,256,1,1,1,0,258,256],
64 | [257,0,0,258,0,1,1,0,256,0,1,1,258,0,1,0,257,0,258,1,1,0,258,256,257,256,256,1,1,0,258,256],
65 | [257,0,0,258,0,1,1,0,0,0,1,1,1,0,258,0,257,0,258,1,1,258,0,1,257,256,256,1,1,0,258,256],
66 | [257,0,0,258,0,1,1,0,0,0,1,1,1,0,258,0,257,0,258,1,1,258,0,257,257,256,256,1,1,0,258,256],
67 | [257,0,257,0,258,0,256,0,256,2,257,0,258,0,256,0,257,0,257,0,258,0,256,0,256,2,257,0,258,0,256,0],
68 | [257,0,1,0,258,0,256,0,256,2,257,0,258,0,256,0,257,0,257,0,258,0,256,0,256,2,257,0,258,0,256,0],
69 | [257,0,1,0,258,0,256,0,1,2,1,0,258,0,256,0,257,0,257,0,258,0,256,0,1,2,257,1,258,0,256,0],
70 | [257,0,1,0,258,0,256,0,1,2,1,0,258,0,256,0,257,0,257,0,258,0,256,2,256,0,257,1,258,0,256,0],
71 | [257,0,1,0,258,0,256,0,2,2,1,1,258,0,256,0,257,0,258,0,258,0,256,0,257,2,1,1,258,0,256,0],
72 | [257,0,256,0,258,0,256,0,2,0,257,1,258,0,256,0,257,0,258,1,258,0,256,0,257,2,1,1,258,0,256,0],
73 | [257,0,256,0,258,0,1,0,0,0,1,1,258,0,256,0,257,0,258,1,258,0,256,2,257,256,1,1,258,0,256,0],
74 | [257,0,0,258,0,1,1,0,256,0,1,1,258,0,256,0,257,0,258,1,1,0,258,256,257,256,1,1,256,0,258,256],
75 | [257,0,0,258,0,1,1,0,256,0,1,1,258,0,256,0,257,0,258,1,1,258,0,1,257,256,1,1,258,0,256,257],
76 | [257,0,0,258,0,1,1,0,0,0,1,1,258,0,256,0,257,0,258,1,1,258,0,257,257,256,256,1,1,0,260,257],
77 | [257,0,0,258,0,1,1,0,0,0,1,1,258,0,1,0,257,0,258,1,1,258,0,257,1,257,256,1,1,0,260,257],
78 | [257,0,257,0,258,0,256,0,256,2,257,0,258,0,256,2,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
79 | [257,0,257,0,258,0,256,0,256,2,257,0,258,0,256,0,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
80 | [257,0,257,0,258,0,256,0,256,2,257,0,258,0,256,0,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
81 | [257,0,1,0,258,0,256,0,2,2,257,1,258,0,256,0,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
82 | [257,0,1,0,258,0,256,0,2,2,1,1,258,0,256,0,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
83 | [257,0,256,0,258,0,256,0,0,2,257,1,258,0,256,0,257,0,258,1,258,0,256,2,257,1,257,1,258,0,256,0],
84 | [257,0,256,0,258,0,1,0,0,0,257,1,258,0,256,0,257,0,258,1,258,0,256,1,257,1,1,1,258,0,256,256],
85 | [257,0,0,258,0,1,1,0,0,0,1,1,258,0,256,0,257,0,258,1,1,2,256,1,257,1,258,1,256,0,258,256],
86 | [257,0,0,258,0,1,1,0,0,0,1,1,258,0,256,0,257,0,258,1,1,2,0,1,257,256,1,1,256,0,260,257],
87 | [257,0,0,258,0,1,1,0,0,0,1,1,258,0,256,0,257,0,258,1,1,1,2,0,257,1,256,257,1,256,256,134],
88 | [257,0,0,258,0,1,1,0,0,258,1,1,258,0,0,0,257,0,258,1,1,1,2,272,257,1,256,264,1,256,256,134],
89 | [257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,2,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
90 | [257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,2,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
91 | [257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,2,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
92 | [257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
93 | [257,0,257,0,258,0,256,0,0,2,257,1,258,0,256,0,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
94 | [257,0,258,0,2,0,256,0,0,2,257,1,258,0,256,0,257,0,258,1,258,0,256,1,256,2,257,1,258,0,256,256],
95 | [257,0,258,0,0,0,256,0,0,0,257,1,258,0,256,0,257,0,258,1,258,0,256,1,257,2,257,1,258,0,256,257],
96 | [257,0,0,258,0,256,1,0,0,0,1,1,258,0,256,0,257,0,258,1,258,2,0,1,257,2,1,1,258,0,256,257],
97 | [257,0,0,258,0,256,1,0,2,0,1,257,258,0,256,0,257,1,258,1,1,1,258,1,257,1,1,1,256,0,260,257],
98 | [257,0,0,258,0,256,1,0,0,258,0,257,1,258,0,0,257,1,1,258,1,1,2,272,257,1,8,1,256,256,256,134],
99 | [257,0,0,2,0,256,1,0,0,258,0,257,1,0,258,0,1,257,1,258,1,64,1,272,1,257,8,264,1,256,4,389],
100 | [257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,2,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
101 | [257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,2,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
102 | [257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,2,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
103 | [257,0,257,0,258,0,256,2,0,2,257,1,258,0,256,2,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
104 | [257,0,257,0,258,0,256,2,0,2,257,1,258,0,256,0,257,1,257,0,258,0,256,2,256,2,257,1,258,0,256,256],
105 | [257,0,258,0,2,0,256,2,0,2,257,1,258,0,256,0,257,1,257,1,258,0,256,1,256,2,257,1,258,0,256,1],
106 | [257,0,258,0,0,0,256,0,0,0,257,1,258,0,256,0,257,1,258,1,258,0,256,1,257,2,257,1,258,0,256,257],
107 | [257,0,0,258,0,256,1,0,0,0,257,1,258,0,256,0,257,1,258,1,1,2,256,1,257,1,258,1,256,256,256,257],
108 | [257,0,0,258,0,256,1,0,0,0,1,257,258,258,0,0,0,257,1,258,1,1,2,16,257,1,1,1,256,256,4,134],
109 | [257,0,0,2,0,256,1,0,0,2,0,257,1,0,0,0,1,257,1,258,1,64,1,16,1,257,8,264,1,256,4,389],
110 | [257,0,0,2,0,256,1,0,0,2,0,257,1,0,258,0,1,257,1,258,1,64,16,272,1,257,8,264,1,256,4,389],
111 | [257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,2,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
112 | [257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,2,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
113 | [257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,2,257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,0],
114 | [257,0,257,0,258,0,256,2,256,2,257,1,258,0,256,2,257,0,257,1,258,0,256,2,256,2,257,1,258,0,256,256],
115 | [257,0,257,0,258,0,256,2,0,2,257,1,258,0,256,0,257,1,257,0,258,1,256,2,256,2,257,1,258,0,256,256],
116 | [257,0,258,0,2,0,256,2,0,2,257,1,258,0,256,0,257,1,257,1,258,0,256,1,256,2,257,1,258,0,256,257],
117 | [257,0,258,0,0,1,256,0,2,0,257,1,258,0,256,0,257,1,257,1,258,1,256,1,2,1,257,1,258,256,256,257],
118 | [257,0,258,2,0,256,1,0,2,0,257,257,0,258,0,0,1,257,1,258,1,1,2,256,16,257,1,257,256,256,0,134],
119 | [257,0,0,258,0,256,1,0,0,2,0,257,1,258,0,0,1,257,1,258,1,64,16,16,1,257,1,264,1,256,4,389],
120 | [257,0,0,2,0,256,1,0,0,2,0,257,1,0,256,0,1,257,1,258,1,64,16,16,1,257,8,264,1,4,256,389],
121 | [257,0,0,2,0,256,257,0,0,2,0,257,1,0,258,0,1,257,1,258,1,64,16,16,1,257,8,264,1,4,4,389]]
122 |
--------------------------------------------------------------------------------
/less/_mixins.less:
--------------------------------------------------------------------------------
1 | .tablet(@rules) {
2 | @media (max-width: 991px) {
3 | @rules();
4 | }
5 | }
6 |
7 | .mobile-landscape(@rules) {
8 | @media only screen and (orientation: landscape) and (max-height: 490px) {
9 | @rules();
10 | }
11 | }
12 |
13 | .mobile(@rules) {
14 | @media (max-width: 479px) {
15 | @rules();
16 | }
17 | }
18 | .transition(@duration, @easeType) {
19 | -webkit-transition: opacity @duration @easeType, color @duration @easeType, background-color @duration @easeType;
20 | transition: opacity @duration @easeType, color @duration @easeType, background-color @duration @easeType;
21 | }
22 |
23 |
24 | .flex() {
25 | display: -webkit-box;
26 | display: -webkit-flex;
27 | display: -ms-flexbox;
28 | display: flex;
29 | }
30 |
31 | .flex-direction(@direction) {
32 | -webkit-flex-direction: @direction;
33 | -ms-flex-direction: @direction;
34 | flex-direction: @direction;
35 | }
36 |
37 | .flex-wrap(@wrap) {
38 | -webkit-flex-wrap: @wrap;
39 | -ms-flex-wrap: @wrap;
40 | flex-wrap: @wrap;
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/less/base-button.less:
--------------------------------------------------------------------------------
1 | .base-button {
2 | &.disabled {
3 | pointer-events: none;
4 | opacity: 0.5;
5 | }
6 | &.active{
7 | min-width: 40px!important;
8 | }
9 | outline: none;
10 | border: none;
11 | .transition(300ms, ease-in-out);
12 | opacity: 1.0;
13 | font-family: 'Poppins', Arial, sans-serif;
14 | color: #fff;
15 | cursor: pointer;
16 | position: relative;
17 | min-height: auto;
18 | width: auto;
19 | min-width: 130px;
20 | padding-left: 20px;
21 | padding-right: 20px;
22 | margin-top: 15px;
23 | padding-top: 10px;
24 | padding-bottom: 7px;
25 | border-radius: 46px;
26 | background-color: #4b4b4b;
27 | font-size: 14px;
28 | line-height: 20px;
29 | text-align: center;
30 | text-transform: uppercase;
31 | transition: min-width 400ms ease-in-out;
32 |
33 |
34 | &:hover {
35 | background-color: #fff;
36 | color: #000;
37 | }
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/less/base-select.less:
--------------------------------------------------------------------------------
1 | @offWhite: rgba(255, 255, 255, 0.8);
2 | .base-select {
3 | // -webkit-appearance: none;
4 | display: block;
5 | width: auto;
6 | height: 19px;
7 | // padding-top: 20px;
8 | text-align-last:center;
9 | // padding: 15px 15px;
10 | // margin-bottom: 15px;
11 | font-size: 16px;
12 | line-height: 20px;
13 | // text-transform: uppercase;
14 | color: @offWhite;
15 | background-color: #4b4b4b; //#ffffff;
16 | border: none; //1px solid @offWhite;
17 | text-align: center;
18 | }
19 |
--------------------------------------------------------------------------------
/less/bpm.less:
--------------------------------------------------------------------------------
1 | #bpm-slider {
2 | .mobile-landscape({
3 | left: 80px !important ;
4 | // left: 60px !important;
5 | });
6 | .mobile({
7 | left: 60px !important;
8 | });
9 | .tablet({
10 | left: 80px;
11 | });
12 | position: relative;
13 | left: 110px;
14 | }
15 |
16 | .bpm-slider {
17 | display: inherit;
18 | &.active {
19 | .bpm-slider-container {
20 | .mobile-landscape({
21 | top: -80px;
22 | });
23 | .tablet({
24 | top:-80px;
25 | });
26 | height: 200px;
27 | top: -74px;
28 | }
29 | .bpm-slider-button {
30 | .mobile-landscape({
31 | top: 80px;
32 | });
33 | .tablet({
34 | top: 80px;
35 | });
36 | top: 74px;
37 | }
38 | }
39 |
40 |
41 | .bpm-slider-button,
42 | .bpm-slider-container {
43 | .bpm-slider-container-device() {
44 | width: 40px;
45 | height: 40px;
46 | }
47 | .mobile-landscape({
48 | .bpm-slider-container-device();
49 | });
50 | .tablet({
51 | .bpm-slider-container-device()
52 | });
53 | position: absolute;
54 |
55 | width: 51px;
56 | height: 51px;
57 | border-radius: 51px;
58 | background-color: #4b4b4b;
59 | }
60 |
61 | .bpm-slider-button {
62 | top: 0px;
63 | cursor: pointer;
64 | background-image: url('../assets/images/tempo.svg');
65 | background-position: 50% 37%;
66 | background-repeat: no-repeat;
67 | transition-property: top;
68 | transition-duration: @transitionDuration;
69 | z-index: 2;
70 | }
71 |
72 | .bpm-slider-container {
73 | position: relative;
74 | overflow: hidden;
75 | .bpm-container-transform(@xPos) {
76 | transform: rotateZ(-90deg) translate(80px, @xPos);
77 | -ms-transform: rotateZ(-90deg) translate(80px, @xPos); /* IE 9 */
78 | -webkit-transform: rotateZ(-90deg) translate(80px, @xPos); /* Safari */
79 |
80 | }
81 |
82 | input[type="range"] {
83 | .mobile-landscape({
84 | -moz-transform: rotateZ(-90deg) translate(80px, -46px) !important;
85 | .bpm-container-transform(-39px);
86 | });
87 | .tablet({
88 | -moz-transform: rotateZ(-90deg) translate(80px, -46px) !important;
89 | .bpm-container-transform(-39px);
90 | });
91 | position: relative;
92 | top: 160px;
93 | width: 115px;
94 | -moz-transform: rotateZ(-90deg) translate(80px, -41px) !important;
95 | .bpm-container-transform(-35px);
96 | }
97 |
98 | transition-property: height, top;
99 | transition-duration: @transitionDuration;
100 | top: 0px;
101 | }
102 |
103 | .bpm-slider-label {
104 |
105 | .bpm-slider-label-device(){
106 |
107 | left: auto;
108 | }
109 |
110 | .mobile-landscape({
111 | font-size: @mobile-font-size;
112 | .bpm-slider-label-device();
113 | });
114 | .tablet({
115 | font-size: @tablet-font-size;
116 | .bpm-slider-label-device();
117 | });
118 |
119 | position: relative;
120 | top:-18px;
121 | max-height: 20px;
122 | min-width: 28px;
123 | transition-property: top;
124 | transition-duration: @transitionDuration;
125 | }
126 |
127 | #pendulumWrapper {
128 | transform: rotate(40deg);
129 | transform-origin: 50% 67%;
130 | transition: transform 300ms ease;
131 | }
132 |
133 | .bpm-icon-line, .bpm-icon-circle {
134 | stroke:#FFF;
135 | stroke-width: 2;
136 | stroke-linecap : round;
137 | stroke-miterlimit : 10;
138 | };
139 |
140 | .bpm-icon-circle {
141 | fill:#4b4b4b;
142 | }
143 | .bpm-icon-line {
144 | fill:none
145 | }
146 |
147 | input[type=range] {
148 | -webkit-appearance: none;
149 | }
150 |
151 | input[type=range]:focus {
152 | outline: none;
153 | }
154 |
155 | @runnable-track: {
156 | width: 100%;
157 | height: 2.3px;
158 | cursor: pointer;
159 | box-shadow: 0px 0px 1px rgba(0, 0, 0, 0), 0px 0px 0px rgba(13, 13, 13, 0);
160 | background: #ffffff;
161 | border-radius: 0px;
162 | border: 0px solid #010101;
163 |
164 |
165 | };
166 |
167 | input[type=range]::-webkit-slider-runnable-track {
168 | @runnable-track();
169 | }
170 | input[type=range]::-moz-range-track {
171 | @runnable-track();
172 | }
173 |
174 | // remove dotted line
175 | input[type=range]::-moz-focus-outer{
176 | border:0;
177 | }
178 |
179 | input[type=range]:focus {outline:none;}
180 |
181 |
182 |
183 | @range-thumb: {
184 | box-shadow: 0px 0px 1.2px rgba(0, 0, 0, 0.16), 0px 0px 0px rgba(13, 13, 13, 0.16);
185 | border: 10px solid rgba(0, 0, 0, 0);
186 | height: 21px;
187 | width: 12px;
188 | border-radius: 50px;
189 | background: #ffffff;
190 | cursor: pointer;
191 | };
192 |
193 | @range-fill: {
194 | border: 0px solid #010101;
195 | border-radius: 0px;
196 | box-shadow: 0px 0px 1px rgba(0, 0, 0, 0), 0px 0px 0px rgba(13, 13, 13, 0);
197 | };
198 |
199 | input[type=range]::-webkit-slider-thumb {
200 | @range-thumb();
201 | -webkit-appearance: none;
202 | margin-top: -9.35px;
203 | }
204 |
205 | input[type=range]::-moz-range-thumb {
206 | @range-thumb();
207 | }
208 | input[type=range]::-ms-track {
209 | @runnable-track();
210 | background: transparent;
211 | border-color: transparent;
212 | color: transparent;
213 | }
214 | input[type=range]::-ms-fill-lower {
215 | background: #fafafa;
216 | @range-fill();
217 | }
218 |
219 | input[type=range]:focus::-ms-fill-lower {
220 | background: #fff;
221 | }
222 | input[type=range]::-ms-fill-upper {
223 | background: #ffffff;
224 | @range-fill();
225 | }
226 | input[type=range]::-ms-thumb {
227 | @range-thumb();
228 | height: 2.3px;
229 | }
230 | input[type=range]:focus::-ms-fill-upper {
231 | background: #fff;
232 | }
233 | }
234 |
235 |
--------------------------------------------------------------------------------
/less/edit-sequencer-button.less:
--------------------------------------------------------------------------------
1 |
2 | .edit-mode-group {
3 | &.active {
4 | opacity: 1.0;
5 | max-height: 1000px;
6 |
7 | }
8 | height: auto;
9 | max-height: 0px;
10 | width: 100%;
11 | margin-left: auto;
12 | margin-right: auto;
13 | opacity: 0.0;
14 | .transition(@transitionDuration, @transitionType);
15 | transition: max-height @transitionDuration @transitionType;
16 | }
17 |
18 | .edit-sequencer-button {
19 | &:hover {
20 | background-color: #fff;
21 | color: #000;
22 | border: 2px solid white;
23 | }
24 | .mobile-landscape({
25 | font-size: 10px;
26 | });
27 | -webkit-appearance: none;
28 | color: #ffffff80;
29 | outline: none;
30 | position: relative;
31 | min-height: auto;
32 | width: 49%;
33 | cursor: pointer;
34 | padding-top: 4px;
35 | margin: 0;
36 | border: 2px solid #4b4b4b;
37 | background-color: #4b4b4b00;
38 | transition: background-color 300ms ease-in-out, color 300ms ease-in-out, border 300ms ease-in-out;
39 | font-size: 14px;
40 | line-height: 22px;
41 | text-align: center;
42 | text-transform: uppercase;
43 | }
44 |
--------------------------------------------------------------------------------
/less/grid-view.less:
--------------------------------------------------------------------------------
1 | body.edit {
2 | #grid-view {
3 | //opacity: 0.25;
4 | pointer-events: none;
5 | }
6 | }
7 |
8 | #grid-view {
9 | user-select: none;
10 | }
11 |
--------------------------------------------------------------------------------
/less/layout.less:
--------------------------------------------------------------------------------
1 | /**
2 | * this is just the basic flex box layout system
3 | */
4 |
5 | .wrapper {
6 | position: absolute;
7 | top: 0;
8 | height: 100%;
9 | width: 100%;
10 | & > * {
11 | padding: 10px;
12 | }
13 | }
14 |
15 |
16 | .waist {
17 | // .mobile-landscape({
18 | // margin-bottom: 100px;
19 | // });
20 | // .tablet({
21 | // margin-bottom: 100px;
22 | // });
23 | // margin: 0;
24 | // padding: 0;
25 | // position: absolute;
26 | // top: 0;
27 | }
28 |
29 | .footer {
30 | .tablet({
31 | height: 40px;
32 | });
33 | .mobile-landscape({
34 | height: 40px;
35 | });
36 | .mobile({
37 | padding-top: 15px;
38 |
39 | });
40 |
41 | position: fixed;
42 | left: 0px;
43 | right: 0px;
44 | bottom: 0px;
45 | display: flex;
46 | height: 75px;
47 | z-index: 1;
48 | // padding: 10px 0px;
49 | justify-content: center;
50 | flex: 1 4 10%;
51 | background-color: #454545;
52 | }
53 |
54 | .aside {
55 | width: 100%;
56 | position: relative;
57 | text-align: center;
58 |
59 | figure {
60 | margin: 0;
61 | }
62 | //box-sizing: border-box;
63 | //border: 1px solid white;
64 | }
65 |
66 | .right-footer-column {
67 | .tablet({
68 | justify-content: right !important;
69 | });
70 | }
71 |
72 | .column {
73 | position: relative;
74 | display: flex;
75 | flex-direction: row;
76 | justify-content: center;
77 | flex-wrap: nowrap;
78 | align-items: center;
79 | align-content: stretch;
80 | flex: 1;
81 | }
82 |
83 | //@media all and (min-width: 600px) {
84 | // .aside { flex: 2 2 auto; }
85 | //}
86 | //
87 | //@media all and (min-width: 800px) {
88 | // .left-column { order: 1; }
89 | // .main { order: 2; }
90 | // .right-column { order: 3; }
91 | // .footer { order: 4; }
92 | //}
93 |
94 |
--------------------------------------------------------------------------------
/less/midi-out.less:
--------------------------------------------------------------------------------
1 |
2 | #midi-output-container {
3 | .mobile-landscape({
4 | display:none;
5 | });
6 |
7 | .tablet({
8 | display:none;
9 | });
10 | position: relative;
11 | top: 0px;
12 |
13 | }
14 |
15 | #midi-out-selector {
16 | outline: none;
17 | cursor: pointer;
18 | height: 27px;
19 | font-family: 'Poppins', Arial, sans-serif;
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/less/modal.less:
--------------------------------------------------------------------------------
1 | /**
2 | these styles are exclusively for the preset links
3 | for things like "amen break"
4 | */
5 |
6 | .modal{
7 | &.active {
8 | visibility: visible !important;
9 | opacity: 1.0;
10 | pointer-events: all;
11 | }
12 | pointer-events: none;
13 | position: absolute;
14 | left: 0px;
15 | top: 0px;
16 | right: 0px;
17 | bottom: 0px;
18 | z-index: 3;
19 | display: block;
20 | width: auto;
21 | height: auto;
22 |
23 | color: rgba(255, 255, 255, 0.5);
24 | background: rgb(33, 33, 33);
25 | opacity: 0.0;
26 | transition: opacity 300ms ease-in-out;
27 |
28 | h2 {
29 | .mobile({
30 | font-size: 20px;
31 | });
32 | }
33 |
34 | .modal-container {
35 |
36 | top: 30px;
37 | transform: translate(-50%, 0px);
38 | padding: 10px 10px 30px 10px;
39 | width: 95%;
40 | position: absolute;
41 | display: flex;
42 | left: 50%;
43 | flex-direction: column;
44 | justify-content: center;
45 | align-items: center;
46 | flex: 1;
47 | color: rgba(255, 255, 255, 0.8);
48 | max-width: 750px;
49 | padding: 10px 10px 10px 10px;
50 | z-index: 2;
51 | // margin-right:auto;
52 | // margin-left: auto;
53 |
54 | }
55 | p {
56 | .mobile({
57 | line-height: 22px;
58 | font-size: 17px;
59 | });
60 | line-height: 28px;
61 | font-size: 22px;
62 | text-align: left;
63 | // letter-spacing: 0.01em;
64 | }
65 | a {
66 | color: @linkColor;
67 | }
68 |
69 | .output-button {
70 |
71 | color: @linkColor;
72 | margin: 20px auto 15px auto ;
73 | padding: 10px;
74 | font-size: 15px;
75 | border: none;
76 | background: none;
77 | outline:none;
78 | }
79 |
80 |
81 |
82 | .base-button {
83 |
84 | &:hover {
85 | color: white;
86 | opacity: 1.0;
87 | background-color: @linkColor;
88 | };
89 | .mobile({
90 | font-size: 15px;
91 | min-width: 120px;
92 | });
93 |
94 | min-width: 162px;
95 | margin-top: 0px;
96 | padding: 12px 10px 10px 10px;
97 | // padding-top: 14px;
98 | opacity: 0.8;
99 | border: 1px solid @linkColor;
100 | background: none;
101 | display: inline-block;
102 | margin: 5px;
103 | font-size: 20px;
104 | transition: background-color 300ms ease-in-out, color 300ms ease-in-out;
105 | }
106 |
107 | .copy-link {
108 | cursor: pointer;
109 | .mobile({
110 | font-size: 15px!important;
111 | });
112 | font-size: 20px;
113 | }
114 | .copy-link.copied {
115 | color: white;
116 | }
117 | .social-container {
118 | display: flex;
119 | flex-direction: row;
120 |
121 | }
122 |
123 | input {
124 | .mobile({
125 | width: 300px;
126 | font-size: 13px;
127 | });
128 | margin-top: 15px;
129 | -webkit-appearance: none;
130 | font-size: 17px;
131 | width: 365px;
132 | height: 30px;
133 | padding: 10px;
134 | outline: none;
135 | border: none;
136 | text-align: center;
137 | border-radius: 2px;
138 | background: none;
139 | color: white;
140 | background-color: rgba(69, 69, 69, 0.8);
141 | }
142 | }
143 |
144 | .video {
145 | .mobile-landscape({
146 | height: 200px;
147 | width: 340px;
148 | });
149 |
150 | .mobile({
151 | height: 300px;;
152 | });
153 | height: 500px;
154 | width: 100%;
155 | }
156 |
157 | .exit {
158 | &:hover{
159 | cursor: pointer;
160 | opacity: 1.0;
161 | }
162 | .exit-device(){
163 | top:10px;
164 | width: 20px;
165 | height: 20px;
166 | }
167 | .tablet({
168 | .exit-device();
169 | });
170 | .mobile-landscape({
171 | .exit-device();
172 | });
173 |
174 | opacity: 0.8;
175 | width: 40px;
176 | height: 40px;
177 | background:transparent;
178 | border: none;
179 | position: absolute;
180 | outline: none;
181 | top: 10px;
182 | right: 10px;
183 | background-image: url('images/exit.svg');
184 | background-position: 50% 50%;
185 | background-size: 30px;
186 | background-repeat: no-repeat;
187 | background-attachment: scroll;
188 | z-index: 3;
189 | transition: opacity 300ms ease-in-out;
190 | }
191 |
--------------------------------------------------------------------------------
/less/play-pause-button.less:
--------------------------------------------------------------------------------
1 |
2 | .play-pause-button {
3 | .play-pause-button-device() {
4 | width: 70px;
5 | height: 70px;
6 | }
7 | .mobile-landscape({
8 | .play-pause-button-device();
9 | });
10 | .tablet({
11 | .play-pause-button-device();
12 | });
13 | .mobile({
14 | width: 65px;
15 | height: 65px;
16 | top: -20px;
17 | });
18 | width: 100px;
19 | height: 100px;
20 | position: absolute;
21 | border: 2px solid #fff;
22 | border-radius: 50%;
23 | top: -25px;
24 | background-color: transparent;
25 | background-image: url('../assets/images/play-button.svg');
26 | background-color: white;
27 | background-position: 55% 50%;
28 | background-repeat: no-repeat;
29 | cursor: pointer;
30 | // transition-property: background-image;
31 | // transition-duration: @transitionDuration;
32 |
33 |
34 | &:focus {
35 | outline: none;
36 | }
37 |
38 | &.active {
39 |
40 | outline: none;
41 | background-image: url('../assets/images/pause-button.svg');
42 | background-position: 50% 50%;
43 | background-size: 21px;
44 | background-repeat: no-repeat;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/less/preset-buttons.less:
--------------------------------------------------------------------------------
1 | /**
2 | these styles are exclusively for the preset links
3 | for things like "amen break"
4 | */
5 |
6 | .preset-button-container {
7 | &.active {
8 | max-height: 1000px;
9 | opacity: 1.0;
10 | }
11 | max-height: 0px;
12 | opacity: 0.0;
13 | height: auto;
14 | overflow: hidden;
15 | margin-left: auto;
16 | margin-right: auto;
17 | transition: max-height 400ms ease-in-out, opacity 300ms ease-in-out;
18 | }
19 |
20 | .preset-button, .generate-new-beat-button {
21 | .tablet({
22 | font-size: 12px!important;
23 | });
24 | .mobile-landscape({
25 | font-size: 10px!important;
26 | margin-top: 0px;
27 | margin-left: 1px;
28 | margin-bottom: 0px;
29 | });
30 | .mobile({
31 | font-size: 14px!important;
32 | });
33 | &.active {
34 | color: rgba(255, 255, 255, 0.75);
35 | }
36 |
37 | &:hover {
38 | color: white;
39 | border-color: white;
40 | }
41 | min-height: auto;
42 | cursor: pointer;
43 | outline: none;
44 | border: none;
45 | // border-bottom: 2px solid;
46 | border-color: rgba(255, 255, 255, 0.5);
47 | color: rgba(255, 255, 255, 0.5);
48 | background-color: transparent;
49 | margin-top: 6px;
50 | margin-left: 10px;
51 | // padding: 4px 0px 4px 0px;
52 | padding: 0px;
53 | font-size: 14px;
54 | // line-height: 20px;
55 | text-transform: uppercase;
56 | transition: background-color 300ms ease-in-out, color 300ms ease-in-out, border-color 300ms ease-in-out;
57 | }
58 |
59 | .generate-new-beat-button {
60 | &.isSafari {
61 | -webkit-text-fill-color: @linkColor !important;
62 | }
63 | background: linear-gradient(270deg, #9da7fa, #e076f7, #9bf8cb, #c5f68f);
64 | background-size: 500% 500%;
65 | background-clip: text;
66 | -webkit-background-clip: text;
67 | -webkit-text-fill-color: transparent;
68 | animation: GradientBlendAnimation 10s ease infinite;
69 | @keyframes GradientBlendAnimation {
70 | 0%{background-position:0% 50%}
71 | 50%{background-position:100% 50%}
72 | 100%{background-position:0% 50%}
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/less/responsive.less:
--------------------------------------------------------------------------------
1 |
2 | /*@media all and (min-width: 600px) {
3 |
4 | .aside {
5 | width: 50%;
6 | float: left;
7 | }
8 |
9 | #sequencer-container {
10 | width: 70%;
11 | margin-left: 10%;
12 | margin-right: 20%;
13 | }
14 |
15 | #grid-container {
16 | width: 70%;
17 | margin-left: 20%;
18 | margin-right: 10%;
19 | }
20 |
21 | }*/
22 |
--------------------------------------------------------------------------------
/less/spinner.less:
--------------------------------------------------------------------------------
1 | @offset: 187;
2 | @duration: 2.4s;
3 |
4 | .spinner {
5 | animation: rotator @duration linear infinite;
6 | }
7 |
8 | @keyframes rotator {
9 | 0% { transform: rotate(0deg); }
10 | 100% { transform: rotate(270deg); }
11 | }
12 |
13 | .path {
14 | stroke-dasharray: @offset;
15 | stroke-dashoffset: 0;
16 | transform-origin: center;
17 | animation:
18 | dash @duration ease-in-out infinite,
19 | colors (@duration*4) ease-in-out infinite;
20 | }
21 |
22 | @keyframes colors {
23 | 0% { stroke: rgba(255,255,255,0.15); }
24 | 25% { stroke: rgba(255,255,255,0.25); }
25 | 50% { stroke: rgba(255,255,255,0.5); }
26 | 75% { stroke: rgba(255,255,255,0.75); }
27 | 100% { stroke: rgba(255,255,255,1); }
28 | }
29 |
30 | @keyframes dash {
31 | 0% { stroke-dashoffset: @offset; }
32 | 50% {
33 | stroke-dashoffset: @offset/2;
34 | transform:rotate(135deg);
35 | }
36 | 100% {
37 | stroke-dashoffset: @offset;
38 | transform:rotate(450deg);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/less/splash.less:
--------------------------------------------------------------------------------
1 | @linkColor: #c5ee94;
2 | body.loading {
3 | .splash {
4 | .splash-icon {
5 | .mobile({
6 | margin-top: 70px!important;
7 | });
8 | }
9 | display: table;
10 | z-index: 2;
11 | position: absolute;
12 | }
13 | }
14 |
15 | .splash, modal-container {
16 | //hidden unless loading
17 | display: none;
18 | width: 100%;
19 | height: 100%;
20 | background-color: #121212;
21 | color: rgba(255,255,255, 0.8);
22 |
23 | h1 {
24 | .mobile({
25 | font-size: 38px;
26 | });
27 | .mobile-landscape({
28 | font-size: 30px;
29 | margin-top: 10px;
30 | });
31 | color: #fff;
32 | font-size: 42px;
33 | letter-spacing: 0.02em;
34 | text-transform: uppercase;
35 | margin-top: 30px;
36 | margin-bottom: 0;
37 | }
38 |
39 | a, a:visited, a:active {
40 | &:hover {
41 | opacity: 1.0;
42 | }
43 | border: none;
44 | opacity: 0.8;
45 | transition: all 300ms ease-in-out;
46 | color: @linkColor;
47 | text-decoration: none;
48 | }
49 |
50 | .how-it-works {
51 | &:hover {
52 | border-bottom: 2px solid @linkColor;
53 | }
54 | }
55 |
56 | .splash-description, .splash-info {
57 | .mobile-landscape({
58 | font-size: 18px;
59 | margin-bottom: 10px;
60 | margin-top: 0px;
61 | });
62 | font-size: 22px;
63 | line-height: 30px;
64 | margin-bottom: 30px;
65 | }
66 |
67 | .splash-info{
68 | color: #9e9e9e;
69 | }
70 |
71 | .splash-play-button {
72 | &:focus {
73 | outline: none;
74 | }
75 |
76 | &:hover {
77 | background-color: @linkColor;
78 | color:white;
79 | }
80 |
81 | .mobile-landscape({
82 | font-size: 18px;
83 | margin-bottom: 10px;
84 | width: 120px;
85 | height: 40px;
86 | });
87 |
88 | cursor: pointer;
89 | margin-left: auto;
90 | margin-right: auto;
91 | margin-bottom: 30px;
92 | font-size: 22px;
93 | display: block;
94 | box-sizing: border-box;
95 | width: 205px;
96 | height: 65px;
97 | border: 2px solid @linkColor;
98 | text-transform: uppercase;
99 | color: @linkColor;
100 | text-align: center;
101 | background-color: #121212;
102 | transition: background-color 300ms ease-in-out, color 300ms ease-in-out;
103 | }
104 |
105 | .splash-wrapper {
106 | .mobile-landscape({
107 | top: 40%;
108 | width: 400px;
109 | });
110 |
111 | .mobile({
112 | width: 300px;
113 | top: 40%;
114 | });
115 | position: absolute;
116 | top: 50%;
117 | left: 50%;
118 | transform: translate(-50%, -50%);
119 | margin-left: auto;
120 | margin-right: auto;
121 | width: 400px;
122 | vertical-align: middle;
123 | }
124 |
125 |
126 | .splash-privacy {
127 | .mobile({
128 | bottom: 2px;
129 | right:50%;
130 | transform: translateX(50%);
131 | // right: 20px;
132 | text-align: center;
133 | font-size: 10px;
134 | });
135 | position: absolute;
136 | bottom: 20px;
137 | right: 20px;
138 | font-size: 12px;
139 | }
140 |
141 | .badge-break {
142 | display: inline-block;
143 | position: relative;
144 | margin-right: 20px;
145 | height: 57px;
146 | background-color: #fff;
147 | opacity: .35;
148 | width: 1px;
149 | }
150 |
151 |
152 |
153 | .badge-wrapper {
154 |
155 | .mobile-landscape({
156 | height: 68px;
157 | width: 300px;
158 | display: flex;
159 | align-items: flex-end;
160 | bottom: 0px;
161 | });
162 |
163 | .mobile({
164 | bottom: 12px;
165 | height: 68px;
166 | width: 300px;
167 | left: 50%;
168 | margin-left: 0px;
169 | transform: translateX(-50%);
170 | align-items: flex-end;
171 | display: flex;
172 | transform: translateX(-50%);
173 | justify-content: space-between;
174 | max-width: auto;
175 | // max-width: auto;
176 | });
177 | position: absolute;
178 | display: inline-block;
179 | bottom: 20px;
180 | left: 20px;
181 | }
182 |
183 | .badge {
184 | &:hover {
185 | opacity: 1.0;
186 | }
187 | transition: opacity 300ms ease-in-out;
188 | transition-duration: 300ms ease-in-out;
189 | opacity: 0.7;
190 | display: inline-block;
191 | position: relative;
192 | margin-right: 20px;
193 | width: 120px;
194 | height: 60px;
195 | background-repeat: no-repeat;
196 | background-size: 100% 100%;
197 | opacity: .7;
198 | overflow: hidden;
199 |
200 | }
201 |
202 | .ai-experiment{
203 | background-image: url('../assets/images/ai-experiment.svg')
204 | }
205 |
206 | .google-friends{
207 | background-image: url('../assets/images/friends-at-google.svg')
208 | }
209 |
210 | .magenta-link {
211 | font-weight: 700;
212 | font-size: 10px;
213 | margin-left: 0;
214 | margin-right: 0;
215 | color: #fff;
216 |
217 | .magenta-logo {
218 | .magenta-logo-device() {
219 | margin-top: 10px;
220 | width: 40px !important;
221 | height: 40px !important;
222 | };
223 | .mobile-landscape({
224 | .magenta-logo-device();
225 | });
226 | .mobile({
227 | .magenta-logo-device();
228 | });
229 | background-image: url('../assets/images/magenta-logo.png');
230 | background-size: 90% 90%;
231 | background-position: 0;
232 | background-repeat: no-repeat;
233 | width: 60px;
234 | height: 60px;
235 | float: left;
236 | }
237 |
238 | .magenta-text {
239 | .magenta-text-device() {
240 | margin-top: 16px;
241 | width: 30px !important;
242 | font-size: 5px !important;
243 | }
244 | .mobile-landscape({
245 | .magenta-text-device();
246 | });
247 | .mobile({
248 | .magenta-text-device();
249 | });
250 | margin-top: 14px;
251 | float: right;
252 | height: 100%;
253 | width: 60px;
254 | color: white;
255 | span {
256 | text-decoration: underline;
257 | color: #c5ee94;
258 | }
259 | }
260 | }
261 |
262 |
263 | }
264 |
265 |
266 |
--------------------------------------------------------------------------------
/less/style.less:
--------------------------------------------------------------------------------
1 | @import '_mixins.less';
2 | @import 'layout.less';
3 | @import 'responsive.less';
4 | @import 'grid-view.less';
5 | @import 'tile.less';
6 | @import 'preset-buttons.less';
7 | @import 'midi-out.less';
8 | @import 'play-pause-button.less';
9 | @import 'edit-sequencer-button.less';
10 | @import 'base-button.less';
11 | @import 'base-select.less';
12 | @import 'toggle.less';
13 | @import 'bpm.less';
14 | @import 'modal.less';
15 | @import 'spinner.less';
16 | @import 'splash.less';
17 |
18 |
19 | @mobile-font-size: 12px;
20 | @tablet-font-size: 12px;
21 |
22 | .medium-font-size {
23 | font-size: 1.0em;
24 | }
25 |
26 | .small-font-size {
27 | font-size: 0.9em;
28 | }
29 |
30 | h3 {
31 | .tablet({
32 | margin-top: 15px !important;
33 | });
34 | .mobile-landscape({
35 | font-size: 0.7em;
36 | margin-top: 10px !important;
37 | });
38 | .mobile({
39 | margin-top: 25px;
40 | });
41 |
42 | margin-top: 15px;
43 | margin-bottom: 0px;
44 | .medium-font-size();
45 | // letter-spacing: 0.03em;
46 | }
47 |
48 | h2 {
49 | .mobile-landscape({
50 | margin-bottom: 5px;
51 | font-size: 0.8em!important;
52 | });
53 | margin: 0px;
54 | }
55 |
56 | .hidden {
57 | display: none;
58 | }
59 |
60 | html, body {
61 | height: 100%;
62 | overflow-x: hidden;
63 | }
64 |
65 | body {
66 | &.loading > *:not(.allow-while-loading) {
67 | display: none;
68 | }
69 | -webkit-text-size-adjust:100%; //prevent text scaling
70 | -moz-text-size-adjust:100%;
71 | -ms-text-size-adjust:100%;
72 | color: white;
73 | margin: 0;
74 | padding: 0em;
75 | overflow: none;
76 | background-color: #212121;
77 | font-family: 'Poppins', Arial, sans-serif;
78 | font-weight: medium;
79 | text-align: center;
80 | }
81 |
82 | a {
83 | text-decoration: none;
84 | }
85 |
86 | .sequencer-label {
87 | text-transform: uppercase;
88 | .medium-font-size();
89 | }
90 |
91 | #share {
92 | margin-right: 48%;
93 | }
94 | .output-button {
95 | &.about-button {
96 | .mobile({
97 | margin-left:30px !important;
98 | });
99 |
100 | }
101 |
102 | &.save-button {
103 | .mobile({
104 | margin-left:10px !important;
105 | });
106 |
107 | }
108 | .mobile-landscape({
109 | font-size: @mobile-font-size;
110 | });
111 | .tablet({
112 | font-size: @tablet-font-size;
113 | });
114 | font-weight: normal;
115 | white-space: nowrap;
116 |
117 | transition-property: color;
118 | transition-duration: 0.5s;
119 | color: rgba(255, 255, 255, 0.8);
120 | margin-left: 20px;
121 | &:hover {
122 | color: white;
123 | }
124 |
125 | }
126 |
127 | // we will show Beat Blender on the splash and about,
128 | // but not the main experience
129 | .header {
130 | visibility: hidden;
131 |
132 | }
133 |
134 | .right-column {
135 | .mobile({
136 | padding-bottom: 150px;
137 | })
138 | }
139 |
140 |
141 | #grid-view, #sequencer-view, .left-column, .right-column, .footer {
142 | -webkit-tap-highlight-color: rgba(0,0,0,0);
143 | -webkit-touch-callout: none;
144 | -webkit-user-select: none;
145 | -khtml-user-select: none;
146 | -moz-user-select: none;
147 | -ms-user-select: none;
148 | user-select: none;
149 | &:focus {
150 | outline: none;
151 | }
152 | }
153 |
154 | .left-column, .right-column {
155 | h1 {
156 |
157 | .mobile({
158 | display: none;
159 | });
160 |
161 | .mobile-landscape({
162 | font-size: 8px;
163 | });
164 |
165 | text-transform: uppercase;
166 | letter-spacing: 0.1em;
167 | text-align: left;
168 | margin-left: 20%;
169 | }
170 | .sequencer-label {
171 | text-align: center;
172 | letter-spacing: 0.1em;
173 | margin-left: 10%;
174 | }
175 |
176 | h1, .sequencer-label {
177 | .mobile({
178 | margin-top: 30px !important;
179 | });
180 |
181 | width: 70%;
182 | padding-top: 5%;
183 | margin-top: 5%;
184 | margin-bottom: 2%;
185 | }
186 | h3 {
187 | letter-spacing: 0.1em;
188 | }
189 | }
190 |
191 |
192 | #grid-container {
193 | position: absolute;
194 | margin-top: 0;
195 | }
196 |
197 | #sequencer-view {
198 | user-select: none;
199 | width: 100%;
200 | }
201 |
202 | #grid-view, #group-corners {
203 | width: 100%;
204 | }
205 |
206 | #group-corners {
207 | position: absolute;
208 | top: 0;
209 | left: 0;
210 | z-index: 1;
211 | height: 100%;
212 | }
213 |
214 |
215 |
216 |
217 | .file-drop{
218 | color: black;
219 |
220 | & input {
221 | position: absolute;
222 | width: 100%;
223 | height: 100%;
224 | opacity: 0;
225 | left: 0px;
226 | top: 0px;
227 | }
228 | }
229 |
230 | .output-menu-container {
231 | .flex();
232 | .flex-direction(row);
233 | .flex-wrap(nowrap);
234 | justify-content: center;
235 | align-items: stretch;
236 |
237 | position: relative;
238 | max-width: 500px;
239 | margin-top: 9%;
240 | margin-right: auto;
241 | margin-left: auto;
242 | }
243 |
244 |
245 | //TODO: modify column left and column right to take these attributes in the footer
246 | #share-space {
247 | margin-right: 50%;
248 | }
249 |
--------------------------------------------------------------------------------
/less/tile.less:
--------------------------------------------------------------------------------
1 |
2 | #group-corners {
3 | position: relative;
4 | }
5 |
6 | .tile {
7 | -webkit-transition: border-radius 300ms ease-in-out;
8 | transition: border-radius 300ms ease-in-out;
9 | width: 60px;
10 | height: 60px;
11 | position: absolute;
12 |
13 |
14 | &.corner {
15 | display: table;
16 | color: white;
17 | font-size: 18px;
18 | font-weight: bolder;
19 | cursor: pointer;
20 | box-sizing: border-box;
21 | background-image:none;
22 | transition: border 200ms ease-in-out;
23 |
24 | .corner-label {
25 | .tablet({
26 | font-size: 12px;
27 | });
28 | .mobile({
29 | font-size: 12px
30 | });
31 | .mobile-landscape({
32 | font-size: 10px
33 | });
34 |
35 | display: table-cell;
36 | vertical-align: middle;
37 | position: relative;
38 | top: 3px;
39 | }
40 |
41 | /*&:hover {
42 | background-image: url('../assets/images/edit.png');
43 | background-position: 50% 50%;
44 | background-size: 28px;
45 | background-repeat: no-repeat;
46 | }*/
47 |
48 |
49 | &.corner-background {
50 | opacity: 0.0;
51 | width: 60px;
52 | height: 60px;
53 | background-image: url('./images/edit.png');
54 | background-position: 50% 50%;
55 | background-size: 28px;
56 | background-repeat: no-repeat;
57 |
58 | &:hover {
59 | opacity: 1;
60 | }
61 | }
62 | }
63 |
64 | &.drag-tile {
65 | border-radius: 0%;
66 | pointer-events: none;
67 | box-sizing: border-box;
68 | display: none;
69 | z-index: 1;
70 | border: 4px solid white;
71 | box-shadow: 0px 0px 4px rgba(0,0,0,0.25);
72 | width: 60px;
73 | height: 60px;
74 | }
75 |
76 | &.tl {
77 | top: 0;
78 | left: 0;
79 | }
80 |
81 | &.tr {
82 | top: 0;
83 | right: 0;
84 | }
85 | &.bl {
86 | .mobile({
87 | bottom: 8px; //10px;
88 | });
89 | bottom: 0; //10px;
90 | left: 0;
91 | }
92 | &.br {
93 | .mobile({
94 | bottom: 8px; //10px;
95 | });
96 | bottom: 0; //10px;
97 | right: 0;
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/less/toggle.less:
--------------------------------------------------------------------------------
1 | @offColor: hsla(0, 0%, 100%, .5);
2 | @onColor: white;
3 | @iconOnColor: #212121;
4 | @iconOffColor: white;
5 | @transitionDuration: 0.5s;
6 | @transitionType: ease-in-out;
7 | @toggleSize: 35px;
8 | @toggleSizeTablet: 20px;
9 |
10 |
11 | #drag-draw-toggle {
12 | .drag-draw-toggle-device() {
13 | margin-left: 0px;
14 | left: 50%;
15 | transform: translateX(-40%);
16 | }
17 | .tablet({
18 | .drag-draw-toggle-device();
19 | });
20 | .mobile-landscape({
21 | .drag-draw-toggle-device();
22 | });
23 | margin-left: 50%;
24 |
25 | .toggle-button {
26 | .tablet({
27 | margin-bottom: 5px;
28 | border-radius: @toggleSizeTablet * 0.5;
29 | });
30 | border-radius: @toggleSize * 0.5;
31 | }
32 | .toggle-slider {
33 | border-radius: 50%;
34 | }
35 | }
36 | .toggle {
37 | position: relative;
38 | display: flex;
39 | flex-direction: row;
40 | justify-content: center;
41 | flex-wrap: nowrap;
42 | align-items: center;
43 | align-content: stretch;
44 | flex: 1;
45 | pointer-events: none;
46 | opacity: 0.5;
47 |
48 | &.active {
49 | cursor: pointer;
50 | pointer-events: all;
51 | opacity: 1;
52 | }
53 |
54 | &.right-selected {
55 | .toggle-label-a {
56 | color: @offColor;
57 | }
58 | .toggle-label-b {
59 | color: @onColor;
60 | }
61 | .toggle-slider {
62 | margin-left: 50%;
63 | }
64 | }
65 |
66 | .toggle-label-a {
67 | color: @onColor;
68 | }
69 | .toggle-label-b {
70 | color: @offColor;
71 | }
72 |
73 | .toggle-button {
74 | .tablet({
75 | width: @toggleSizeTablet * 2;
76 | height: @toggleSizeTablet;
77 | });
78 | position: relative;
79 | width: @toggleSize * 2;
80 | height: @toggleSize;
81 | margin-right: 0px;
82 | margin-left: 0px;
83 | background-color: #4b4b4b;
84 | cursor: pointer;
85 | }
86 |
87 |
88 | .toggle-slider {
89 | .tablet({
90 | width: @toggleSizeTablet;
91 | height: @toggleSizeTablet;
92 | });
93 | position: relative;
94 | // z-index: 2;
95 | width: @toggleSize;
96 | height: @toggleSize;
97 | background-color: #fff;
98 | margin-left: 0px;
99 | transition-property: margin;
100 | transition-duration: @transitionDuration;
101 |
102 | }
103 |
104 | .toggle-label {
105 | .toggle-label-device() {
106 | margin-right: 5px;
107 | margin-left: 5px;
108 | }
109 | .mobile-landscape({
110 | font-size: @mobile-font-size;
111 | .toggle-label-device();
112 | });
113 | .tablet({
114 | font-size: @tablet-font-size;
115 | .toggle-label-device();
116 | });
117 | position: static;
118 | overflow: visible;
119 | margin-left: 15px;
120 | margin-right: 15px;
121 |
122 | transition-property: color;
123 | transition-duration: @transitionDuration;
124 | }
125 | }
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright 2017 Google Inc.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 | import os
18 | import webapp2
19 | import urllib2
20 | class Redirect( webapp2.RequestHandler ):
21 | def get(self):
22 | self.redirect('/ai/beat-blender/view/')
23 | app = webapp2.WSGIApplication([
24 | ('/ai/beat-blender/view', Redirect),
25 | ('/', Redirect),
26 | ], debug=True)
27 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "beat-blender",
3 | "version": "0.2.0",
4 | "description": "use machine learning to explore the latent space between drum beats",
5 | "main": "js/index.js",
6 | "gcloud": {
7 | "production": {
8 | "id": "gweb-beat-blender",
9 | "version": "comingsoon"
10 | },
11 | "dev": {
12 | "id": "ml-loopz-demo",
13 | "version": "qa"
14 | },
15 | "devPort": 8080,
16 | "devAdminPort": 8000
17 | },
18 | "browserify": {
19 | "transform": [
20 | [
21 | "babelify",
22 | {
23 | "presets": [
24 | [
25 | "env",
26 | {
27 | "targets": {
28 | "browsers": [
29 | "last 2 versions",
30 | "safari >= 7"
31 | ]
32 | }
33 | }
34 | ]
35 | ]
36 | }
37 | ]
38 | ]
39 | },
40 | "scripts": {
41 | "deploy-production": "npm run build && gcloud app deploy --project $npm_package_gcloud_production_id --version $npm_package_gcloud_production_version",
42 | "deploy-staging": "npm run build && gcloud app deploy --project $npm_package_gcloud_production_id --version staging --no-promote --quiet",
43 | "deploy-dev": "npm run build && gcloud app deploy --project $npm_package_gcloud_dev_id --version $npm_package_gcloud_dev_version --quiet",
44 | "dev_appserver": "dev_appserver.py app.yaml --port=$npm_package_gcloud_devPort --admin_port=$npm_package_gcloud_devAdminPort --host=0.0.0.0",
45 | "browse": "gcloud app browse --project $npm_package_gcloud_id",
46 | "build": "npm run less && browserify js/index.js -o assets/bundle.js",
47 | "less": "lessc less/style.less assets/style.css",
48 | "start": "npm run less && concurrently \"npm run watchify\" \"autoless less/ assets/\" \"npm run dev_appserver\"",
49 | "watchify": "watchify js/index.js --debug -o assets/bundle.js --verbose"
50 | },
51 | "author": "Google Creative Lab",
52 | "contributors": [
53 | "Kyle Phillips",
54 | "Torin Blankensmith"
55 | ],
56 | "license": "Apache-2.0",
57 | "dependencies": {
58 | "autoless": "^0.1.7",
59 | "babel-core": "^6.26.0",
60 | "babel-preset-env": "^1.6.1",
61 | "babelify": "^8.0.0",
62 | "browserify": "^14.5.0",
63 | "concurrently": "^3.5.0",
64 | "debounce": "^1.1.0",
65 | "less": "^2.7.3",
66 | "query-string": "^6.0.0",
67 | "shortid": "^2.2.8",
68 | "tone": "^0.11.11",
69 | "watchify": "^3.9.0",
70 | "whatwg-fetch": "^2.0.3",
71 | "@magenta/music-vae": "^1.0.3",
72 | "startaudiocontext" : "^1.2.1"
73 | },
74 | "devDependencies": {
75 | "animitter": "^3.0.0",
76 | "assert": "^1.4.1",
77 | "dat-gui": "^0.5.0",
78 | "deep-extend": "^0.5.0",
79 | "eases": "^1.0.8",
80 | "event-map": "^2.0.0",
81 | "grid2d": "^1.0.0",
82 | "mixin-deep": "^1.3.1",
83 | "object-assign": "^4.1.1",
84 | "object-path": "^0.11.4",
85 | "page": "^1.8.3",
86 | "throttleit": "^1.0.0",
87 | "tone-piano": "^0.0.5"
88 | }
89 | }
90 |
--------------------------------------------------------------------------------