├── .gitignore
├── README.md
├── blank.html
├── index.html
├── now.json
├── package-lock.json
├── package.json
├── public
├── _boilerplate
│ ├── index.html
│ ├── main.js
│ ├── sonic-pi-beat.rb
│ └── styles.css
├── blank.html
├── css
│ ├── global.css
│ └── grid.css
├── graphs
│ ├── css
│ │ └── notes.css
│ ├── index.html
│ └── js
│ │ └── notes.js
├── index.html
├── js
│ └── slides-setup.js
├── matrix-16x8
│ ├── example-sonic-pi-driver.rb
│ ├── index.html
│ ├── matrix-visualizer.js
│ └── styles.css
├── samples
│ ├── BD.WAV
│ ├── CB.WAV
│ ├── CH.WAV
│ ├── CL.WAV
│ ├── CP.WAV
│ ├── OH.WAV
│ ├── SD.WAV
│ ├── hotline-1-4s.wav
│ ├── hotline-2-4s.wav
│ ├── hotline-3-7s.wav
│ ├── hotline-4-3.5s.wav
│ ├── hotline-5-3.5s.wav
│ ├── thug-01.wav
│ ├── thug-02.wav
│ └── thug-03.wav
└── sqcr-demo
│ ├── buffers
│ ├── init.js
│ ├── loops.js
│ └── synths.js
│ ├── config
│ ├── matrix.json
│ └── presentation.json
│ ├── css
│ └── slides.css
│ ├── html
│ ├── 808.html
│ ├── akai.html
│ ├── beats-graph.html
│ ├── chords-graph.html
│ ├── matrix-16x8.html
│ ├── notes-graph.html
│ ├── random-tones.html
│ └── scale-tones.html
│ ├── js
│ ├── chords-graph-synth.js
│ ├── hats-graph-synth.js
│ ├── matrix-16x8-init.js
│ ├── matrix-16x8-synths.js
│ ├── matrix-16x8.js
│ └── notes-graph-synth.js
│ ├── lib
│ ├── Tone.min.js
│ ├── audiosynth.js
│ ├── osc-browser.js
│ ├── tonal.js
│ └── transpiled.js
│ ├── main.js
│ ├── md
│ └── generative-hip-hop-slides.md
│ ├── renderers
│ ├── matrix-renderer.js
│ └── slider.js
│ ├── sqcr-setup.js
│ ├── styles.css
│ └── visualizer.js
└── src
└── Markov.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Markov Music JS
2 |
3 | A few examples of how to use markov chains to make music.
4 |
5 | Live URL: [markov-music.now.sh](https://markov-music.now.sh)
6 |
7 | ## Locel Setup
8 |
9 | ```
10 | npm install
11 | npm start:slides
12 | ```
13 |
14 | Visit `localhost:8081`
15 |
--------------------------------------------------------------------------------
/blank.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/blank.html
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Markov Music JS
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/now.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "static",
3 | "name": "markov-music-js",
4 | "alias": ["markov-music"],
5 | "files": ["index.html", "blank.html", "src", "node_modules", "public"]
6 | }
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "markov-music-js",
3 | "main": "index.js",
4 | "version": "0.0.1",
5 | "description":
6 | "Example of how to use markov chaining to make music in javascript",
7 | "author": "Omar Delarosa",
8 | "scripts": {
9 | "start:slides": "npm run start:sqcr-demo:slider",
10 | "start:sqcr-demo:matrix":
11 | "sqcr public/sqcr-demo/buffers --config public/sqcr-demo/config/matrix.json --path .",
12 | "start:sqcr-demo:slider":
13 | "sqcr public/sqcr-demo/buffers --config public/sqcr-demo/config/presentation.json --path ."
14 | },
15 | "dependencies": {
16 | "express": "4.16.3",
17 | "meow": "5.0.0",
18 | "sqcr": "omardelarosa/sqcr#release-v1.1.1",
19 | "tonal": "1.1.3",
20 | "tone": "0.12.80",
21 | "vis": "4.21.0",
22 | "webmidi": "2.2.0",
23 | "ws": "5.1.1"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/public/_boilerplate/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Untitled - osc.js demo
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/public/_boilerplate/main.js:
--------------------------------------------------------------------------------
1 | // DATA container
2 | let data = [];
3 |
4 |
5 | // OSC.js stuff
6 | const handleMessage = (msg) => {
7 | // console.log('MSG', msg);
8 | data = msg.address.split('/');
9 | }
10 |
11 | const initOSC = () => {
12 | // Init container
13 |
14 | // Init port
15 | oscPort = new osc.WebSocketPort({
16 | url: "ws://localhost:8081"
17 | });
18 |
19 |
20 | // listen
21 | oscPort.on('message', (msg) => {
22 | handleMessage(msg); // Debugging
23 | });
24 |
25 | // open port
26 | oscPort.open();
27 | };
28 |
29 | // used later to start OSC
30 | window.initOSC = initOSC();
31 |
32 | // Additional code below
33 |
--------------------------------------------------------------------------------
/public/_boilerplate/sonic-pi-beat.rb:
--------------------------------------------------------------------------------
1 | T = 4.0
2 |
3 | use_osc "192.168.1.7", 57121 # this synchronizes with the OSC server in the window. <-
4 |
5 | kick_patterns = [
6 | (bools, 1,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0), # Kick Pattern 1 / C
7 | (bools, 1,0,0,0, 0,0,1,0, 0,1,1,0, 0,1,1,0) # Kick Pattern 2 / C
8 | ].ring
9 |
10 | snare_patterns = [
11 | (bools, 0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0), # Snare Pattern 1 / G
12 | (bools, 0,0,0,0, 1,1,0,0, 0,0,0,0, 1,0,1,0) # Snare Pattern 2 / G
13 | ].ring
14 |
15 | live_loop :kicks do
16 | p = kick_patterns.choose
17 | 16.times do |n|
18 | sample :bd_mehackit if p.tick
19 | osc "/blink/#{n}/#{n/2}/2" if p.look
20 | sleep T/16
21 | end
22 | end
23 |
24 | live_loop :snares do
25 | p = snare_patterns.choose
26 | 16.times do |n|
27 | sample :sn_dolf if p.tick
28 | osc "/blink/#{n}/#{n/2}/3" if p.look
29 | sleep T/16
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/public/_boilerplate/styles.css:
--------------------------------------------------------------------------------
1 | /** Add css here **/
2 |
--------------------------------------------------------------------------------
/public/blank.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | BLANK
5 |
10 |
11 |
12 | Loading...
13 |
14 |
15 |
--------------------------------------------------------------------------------
/public/css/global.css:
--------------------------------------------------------------------------------
1 | body,
2 | html,
3 | div {
4 | background-color: black;
5 | padding: 0;
6 | margin: 0;
7 | color: white;
8 | font-family: 'Helvetica', sans-serif;
9 | }
10 |
11 | .container {
12 | margin-left: auto;
13 | margin-right: auto;
14 | }
15 |
16 | .k-row {
17 | margin-left: auto;
18 | margin-right: auto;
19 | max-width: 1600px;
20 | }
21 |
--------------------------------------------------------------------------------
/public/css/grid.css:
--------------------------------------------------------------------------------
1 | div {
2 | min-height: 90px;
3 | padding: 30px;
4 | }
5 | body {
6 | background: #008080;
7 | padding: 0;
8 | margin: 0;
9 | }
10 | html {
11 | box-sizing: border-box;
12 | }
13 | *,
14 | *:before,
15 | *:after {
16 | box-sizing: inherit;
17 | }
18 | .k-center {
19 | text-align: center;
20 | }
21 | .k-container {
22 | width: 100%;
23 | height: 100%;
24 | display: block;
25 | max-width: 1600px;
26 | }
27 | .k-centered {
28 | margin-left: auto;
29 | margin-right: auto;
30 | }
31 | .k-row {
32 | max-width: 1600px;
33 | }
34 | .k-row:after {
35 | display: table;
36 | clear: both;
37 | content: '';
38 | }
39 | .k-col.k-c-1 {
40 | width: calc(calc(100% - 20px) / 1);
41 | margin-right: 10px;
42 | margin-left: 10px;
43 | float: left;
44 | }
45 | .k-col.k-c-2 {
46 | width: calc(calc(100% - 40px) / 2);
47 | margin-right: 10px;
48 | margin-left: 10px;
49 | float: left;
50 | }
51 | .k-col.k-c-3 {
52 | width: calc(calc(100% - 60px) / 3);
53 | margin-right: 10px;
54 | margin-left: 10px;
55 | float: left;
56 | }
57 | .k-col.k-c-4 {
58 | width: calc(calc(100% - 80px) / 4);
59 | margin-right: 10px;
60 | margin-left: 10px;
61 | float: left;
62 | }
63 | .k-col.k-c-5 {
64 | width: calc(calc(100% - 100px) / 5);
65 | margin-right: 10px;
66 | margin-left: 10px;
67 | float: left;
68 | }
69 | .k-col.k-c-6 {
70 | width: calc(calc(100% - 120px) / 6);
71 | margin-right: 10px;
72 | margin-left: 10px;
73 | float: left;
74 | }
75 | .k-col.k-c-7 {
76 | width: calc(calc(100% - 140px) / 7);
77 | margin-right: 10px;
78 | margin-left: 10px;
79 | float: left;
80 | }
81 | .k-col.k-c-8 {
82 | width: calc(calc(100% - 160px) / 8);
83 | margin-right: 10px;
84 | margin-left: 10px;
85 | float: left;
86 | }
87 | .k-col.k-c-9 {
88 | width: calc(calc(100% - 180px) / 9);
89 | margin-right: 10px;
90 | margin-left: 10px;
91 | float: left;
92 | }
93 | .k-col.k-c-10 {
94 | width: calc(calc(100% - 200px) / 10);
95 | margin-right: 10px;
96 | margin-left: 10px;
97 | float: left;
98 | }
99 | .k-col.k-c-11 {
100 | width: calc(calc(100% - 220px) / 11);
101 | margin-right: 10px;
102 | margin-left: 10px;
103 | float: left;
104 | }
105 | .k-col.k-c-12 {
106 | width: calc(calc(100% - 240px) / 12);
107 | margin-right: 10px;
108 | margin-left: 10px;
109 | float: left;
110 | }
111 | .k-col.k-c-13 {
112 | width: calc(calc(100% - 260px) / 13);
113 | margin-right: 10px;
114 | margin-left: 10px;
115 | float: left;
116 | }
117 | .k-col.k-c-14 {
118 | width: calc(calc(100% - 280px) / 14);
119 | margin-right: 10px;
120 | margin-left: 10px;
121 | float: left;
122 | }
123 | .k-col.k-c-15 {
124 | width: calc(calc(100% - 300px) / 15);
125 | margin-right: 10px;
126 | margin-left: 10px;
127 | float: left;
128 | }
129 | .k-col.k-c-16 {
130 | width: calc(calc(100% - 320px) / 16);
131 | margin-right: 10px;
132 | margin-left: 10px;
133 | float: left;
134 | }
135 | @media (min-width: 0px) {
136 | .k-col.k-c-1-xs {
137 | width: calc(calc(100% - 20px) / 1);
138 | margin-right: 10px;
139 | margin-left: 10px;
140 | float: left;
141 | }
142 | }
143 | @media (min-width: 0px) {
144 | .k-col.k-c-2-xs {
145 | width: calc(calc(100% - 40px) / 2);
146 | margin-right: 10px;
147 | margin-left: 10px;
148 | float: left;
149 | }
150 | }
151 | @media (min-width: 0px) {
152 | .k-col.k-c-3-xs {
153 | width: calc(calc(100% - 60px) / 3);
154 | margin-right: 10px;
155 | margin-left: 10px;
156 | float: left;
157 | }
158 | }
159 | @media (min-width: 0px) {
160 | .k-col.k-c-4-xs {
161 | width: calc(calc(100% - 80px) / 4);
162 | margin-right: 10px;
163 | margin-left: 10px;
164 | float: left;
165 | }
166 | }
167 | @media (min-width: 0px) {
168 | .k-col.k-c-5-xs {
169 | width: calc(calc(100% - 100px) / 5);
170 | margin-right: 10px;
171 | margin-left: 10px;
172 | float: left;
173 | }
174 | }
175 | @media (min-width: 0px) {
176 | .k-col.k-c-6-xs {
177 | width: calc(calc(100% - 120px) / 6);
178 | margin-right: 10px;
179 | margin-left: 10px;
180 | float: left;
181 | }
182 | }
183 | @media (min-width: 0px) {
184 | .k-col.k-c-7-xs {
185 | width: calc(calc(100% - 140px) / 7);
186 | margin-right: 10px;
187 | margin-left: 10px;
188 | float: left;
189 | }
190 | }
191 | @media (min-width: 0px) {
192 | .k-col.k-c-8-xs {
193 | width: calc(calc(100% - 160px) / 8);
194 | margin-right: 10px;
195 | margin-left: 10px;
196 | float: left;
197 | }
198 | }
199 | @media (min-width: 0px) {
200 | .k-col.k-c-9-xs {
201 | width: calc(calc(100% - 180px) / 9);
202 | margin-right: 10px;
203 | margin-left: 10px;
204 | float: left;
205 | }
206 | }
207 | @media (min-width: 0px) {
208 | .k-col.k-c-10-xs {
209 | width: calc(calc(100% - 200px) / 10);
210 | margin-right: 10px;
211 | margin-left: 10px;
212 | float: left;
213 | }
214 | }
215 | @media (min-width: 0px) {
216 | .k-col.k-c-11-xs {
217 | width: calc(calc(100% - 220px) / 11);
218 | margin-right: 10px;
219 | margin-left: 10px;
220 | float: left;
221 | }
222 | }
223 | @media (min-width: 0px) {
224 | .k-col.k-c-12-xs {
225 | width: calc(calc(100% - 240px) / 12);
226 | margin-right: 10px;
227 | margin-left: 10px;
228 | float: left;
229 | }
230 | }
231 | @media (min-width: 0px) {
232 | .k-col.k-c-13-xs {
233 | width: calc(calc(100% - 260px) / 13);
234 | margin-right: 10px;
235 | margin-left: 10px;
236 | float: left;
237 | }
238 | }
239 | @media (min-width: 0px) {
240 | .k-col.k-c-14-xs {
241 | width: calc(calc(100% - 280px) / 14);
242 | margin-right: 10px;
243 | margin-left: 10px;
244 | float: left;
245 | }
246 | }
247 | @media (min-width: 0px) {
248 | .k-col.k-c-15-xs {
249 | width: calc(calc(100% - 300px) / 15);
250 | margin-right: 10px;
251 | margin-left: 10px;
252 | float: left;
253 | }
254 | }
255 | @media (min-width: 0px) {
256 | .k-col.k-c-16-xs {
257 | width: calc(calc(100% - 320px) / 16);
258 | margin-right: 10px;
259 | margin-left: 10px;
260 | float: left;
261 | }
262 | }
263 | @media (min-width: 400px) {
264 | .k-col.k-c-1-s {
265 | width: calc(calc(100% - 20px) / 1);
266 | margin-right: 10px;
267 | margin-left: 10px;
268 | float: left;
269 | }
270 | }
271 | @media (min-width: 400px) {
272 | .k-col.k-c-2-s {
273 | width: calc(calc(100% - 40px) / 2);
274 | margin-right: 10px;
275 | margin-left: 10px;
276 | float: left;
277 | }
278 | }
279 | @media (min-width: 400px) {
280 | .k-col.k-c-3-s {
281 | width: calc(calc(100% - 60px) / 3);
282 | margin-right: 10px;
283 | margin-left: 10px;
284 | float: left;
285 | }
286 | }
287 | @media (min-width: 400px) {
288 | .k-col.k-c-4-s {
289 | width: calc(calc(100% - 80px) / 4);
290 | margin-right: 10px;
291 | margin-left: 10px;
292 | float: left;
293 | }
294 | }
295 | @media (min-width: 400px) {
296 | .k-col.k-c-5-s {
297 | width: calc(calc(100% - 100px) / 5);
298 | margin-right: 10px;
299 | margin-left: 10px;
300 | float: left;
301 | }
302 | }
303 | @media (min-width: 400px) {
304 | .k-col.k-c-6-s {
305 | width: calc(calc(100% - 120px) / 6);
306 | margin-right: 10px;
307 | margin-left: 10px;
308 | float: left;
309 | }
310 | }
311 | @media (min-width: 400px) {
312 | .k-col.k-c-7-s {
313 | width: calc(calc(100% - 140px) / 7);
314 | margin-right: 10px;
315 | margin-left: 10px;
316 | float: left;
317 | }
318 | }
319 | @media (min-width: 400px) {
320 | .k-col.k-c-8-s {
321 | width: calc(calc(100% - 160px) / 8);
322 | margin-right: 10px;
323 | margin-left: 10px;
324 | float: left;
325 | }
326 | }
327 | @media (min-width: 400px) {
328 | .k-col.k-c-9-s {
329 | width: calc(calc(100% - 180px) / 9);
330 | margin-right: 10px;
331 | margin-left: 10px;
332 | float: left;
333 | }
334 | }
335 | @media (min-width: 400px) {
336 | .k-col.k-c-10-s {
337 | width: calc(calc(100% - 200px) / 10);
338 | margin-right: 10px;
339 | margin-left: 10px;
340 | float: left;
341 | }
342 | }
343 | @media (min-width: 400px) {
344 | .k-col.k-c-11-s {
345 | width: calc(calc(100% - 220px) / 11);
346 | margin-right: 10px;
347 | margin-left: 10px;
348 | float: left;
349 | }
350 | }
351 | @media (min-width: 400px) {
352 | .k-col.k-c-12-s {
353 | width: calc(calc(100% - 240px) / 12);
354 | margin-right: 10px;
355 | margin-left: 10px;
356 | float: left;
357 | }
358 | }
359 | @media (min-width: 400px) {
360 | .k-col.k-c-13-s {
361 | width: calc(calc(100% - 260px) / 13);
362 | margin-right: 10px;
363 | margin-left: 10px;
364 | float: left;
365 | }
366 | }
367 | @media (min-width: 400px) {
368 | .k-col.k-c-14-s {
369 | width: calc(calc(100% - 280px) / 14);
370 | margin-right: 10px;
371 | margin-left: 10px;
372 | float: left;
373 | }
374 | }
375 | @media (min-width: 400px) {
376 | .k-col.k-c-15-s {
377 | width: calc(calc(100% - 300px) / 15);
378 | margin-right: 10px;
379 | margin-left: 10px;
380 | float: left;
381 | }
382 | }
383 | @media (min-width: 400px) {
384 | .k-col.k-c-16-s {
385 | width: calc(calc(100% - 320px) / 16);
386 | margin-right: 10px;
387 | margin-left: 10px;
388 | float: left;
389 | }
390 | }
391 | @media (min-width: 600px) {
392 | .k-col.k-c-1-m {
393 | width: calc(calc(100% - 20px) / 1);
394 | margin-right: 10px;
395 | margin-left: 10px;
396 | float: left;
397 | }
398 | }
399 | @media (min-width: 600px) {
400 | .k-col.k-c-2-m {
401 | width: calc(calc(100% - 40px) / 2);
402 | margin-right: 10px;
403 | margin-left: 10px;
404 | float: left;
405 | }
406 | }
407 | @media (min-width: 600px) {
408 | .k-col.k-c-3-m {
409 | width: calc(calc(100% - 60px) / 3);
410 | margin-right: 10px;
411 | margin-left: 10px;
412 | float: left;
413 | }
414 | }
415 | @media (min-width: 600px) {
416 | .k-col.k-c-4-m {
417 | width: calc(calc(100% - 80px) / 4);
418 | margin-right: 10px;
419 | margin-left: 10px;
420 | float: left;
421 | }
422 | }
423 | @media (min-width: 600px) {
424 | .k-col.k-c-5-m {
425 | width: calc(calc(100% - 100px) / 5);
426 | margin-right: 10px;
427 | margin-left: 10px;
428 | float: left;
429 | }
430 | }
431 | @media (min-width: 600px) {
432 | .k-col.k-c-6-m {
433 | width: calc(calc(100% - 120px) / 6);
434 | margin-right: 10px;
435 | margin-left: 10px;
436 | float: left;
437 | }
438 | }
439 | @media (min-width: 600px) {
440 | .k-col.k-c-7-m {
441 | width: calc(calc(100% - 140px) / 7);
442 | margin-right: 10px;
443 | margin-left: 10px;
444 | float: left;
445 | }
446 | }
447 | @media (min-width: 600px) {
448 | .k-col.k-c-8-m {
449 | width: calc(calc(100% - 160px) / 8);
450 | margin-right: 10px;
451 | margin-left: 10px;
452 | float: left;
453 | }
454 | }
455 | @media (min-width: 600px) {
456 | .k-col.k-c-9-m {
457 | width: calc(calc(100% - 180px) / 9);
458 | margin-right: 10px;
459 | margin-left: 10px;
460 | float: left;
461 | }
462 | }
463 | @media (min-width: 600px) {
464 | .k-col.k-c-10-m {
465 | width: calc(calc(100% - 200px) / 10);
466 | margin-right: 10px;
467 | margin-left: 10px;
468 | float: left;
469 | }
470 | }
471 | @media (min-width: 600px) {
472 | .k-col.k-c-11-m {
473 | width: calc(calc(100% - 220px) / 11);
474 | margin-right: 10px;
475 | margin-left: 10px;
476 | float: left;
477 | }
478 | }
479 | @media (min-width: 600px) {
480 | .k-col.k-c-12-m {
481 | width: calc(calc(100% - 240px) / 12);
482 | margin-right: 10px;
483 | margin-left: 10px;
484 | float: left;
485 | }
486 | }
487 | @media (min-width: 600px) {
488 | .k-col.k-c-13-m {
489 | width: calc(calc(100% - 260px) / 13);
490 | margin-right: 10px;
491 | margin-left: 10px;
492 | float: left;
493 | }
494 | }
495 | @media (min-width: 600px) {
496 | .k-col.k-c-14-m {
497 | width: calc(calc(100% - 280px) / 14);
498 | margin-right: 10px;
499 | margin-left: 10px;
500 | float: left;
501 | }
502 | }
503 | @media (min-width: 600px) {
504 | .k-col.k-c-15-m {
505 | width: calc(calc(100% - 300px) / 15);
506 | margin-right: 10px;
507 | margin-left: 10px;
508 | float: left;
509 | }
510 | }
511 | @media (min-width: 600px) {
512 | .k-col.k-c-16-m {
513 | width: calc(calc(100% - 320px) / 16);
514 | margin-right: 10px;
515 | margin-left: 10px;
516 | float: left;
517 | }
518 | }
519 | @media (min-width: 800px) {
520 | .k-col.k-c-1-l {
521 | width: calc(calc(100% - 20px) / 1);
522 | margin-right: 10px;
523 | margin-left: 10px;
524 | float: left;
525 | }
526 | }
527 | @media (min-width: 800px) {
528 | .k-col.k-c-2-l {
529 | width: calc(calc(100% - 40px) / 2);
530 | margin-right: 10px;
531 | margin-left: 10px;
532 | float: left;
533 | }
534 | }
535 | @media (min-width: 800px) {
536 | .k-col.k-c-3-l {
537 | width: calc(calc(100% - 60px) / 3);
538 | margin-right: 10px;
539 | margin-left: 10px;
540 | float: left;
541 | }
542 | }
543 | @media (min-width: 800px) {
544 | .k-col.k-c-4-l {
545 | width: calc(calc(100% - 80px) / 4);
546 | margin-right: 10px;
547 | margin-left: 10px;
548 | float: left;
549 | }
550 | }
551 | @media (min-width: 800px) {
552 | .k-col.k-c-5-l {
553 | width: calc(calc(100% - 100px) / 5);
554 | margin-right: 10px;
555 | margin-left: 10px;
556 | float: left;
557 | }
558 | }
559 | @media (min-width: 800px) {
560 | .k-col.k-c-6-l {
561 | width: calc(calc(100% - 120px) / 6);
562 | margin-right: 10px;
563 | margin-left: 10px;
564 | float: left;
565 | }
566 | }
567 | @media (min-width: 800px) {
568 | .k-col.k-c-7-l {
569 | width: calc(calc(100% - 140px) / 7);
570 | margin-right: 10px;
571 | margin-left: 10px;
572 | float: left;
573 | }
574 | }
575 | @media (min-width: 800px) {
576 | .k-col.k-c-8-l {
577 | width: calc(calc(100% - 160px) / 8);
578 | margin-right: 10px;
579 | margin-left: 10px;
580 | float: left;
581 | }
582 | }
583 | @media (min-width: 800px) {
584 | .k-col.k-c-9-l {
585 | width: calc(calc(100% - 180px) / 9);
586 | margin-right: 10px;
587 | margin-left: 10px;
588 | float: left;
589 | }
590 | }
591 | @media (min-width: 800px) {
592 | .k-col.k-c-10-l {
593 | width: calc(calc(100% - 200px) / 10);
594 | margin-right: 10px;
595 | margin-left: 10px;
596 | float: left;
597 | }
598 | }
599 | @media (min-width: 800px) {
600 | .k-col.k-c-11-l {
601 | width: calc(calc(100% - 220px) / 11);
602 | margin-right: 10px;
603 | margin-left: 10px;
604 | float: left;
605 | }
606 | }
607 | @media (min-width: 800px) {
608 | .k-col.k-c-12-l {
609 | width: calc(calc(100% - 240px) / 12);
610 | margin-right: 10px;
611 | margin-left: 10px;
612 | float: left;
613 | }
614 | }
615 | @media (min-width: 800px) {
616 | .k-col.k-c-13-l {
617 | width: calc(calc(100% - 260px) / 13);
618 | margin-right: 10px;
619 | margin-left: 10px;
620 | float: left;
621 | }
622 | }
623 | @media (min-width: 800px) {
624 | .k-col.k-c-14-l {
625 | width: calc(calc(100% - 280px) / 14);
626 | margin-right: 10px;
627 | margin-left: 10px;
628 | float: left;
629 | }
630 | }
631 | @media (min-width: 800px) {
632 | .k-col.k-c-15-l {
633 | width: calc(calc(100% - 300px) / 15);
634 | margin-right: 10px;
635 | margin-left: 10px;
636 | float: left;
637 | }
638 | }
639 | @media (min-width: 800px) {
640 | .k-col.k-c-16-l {
641 | width: calc(calc(100% - 320px) / 16);
642 | margin-right: 10px;
643 | margin-left: 10px;
644 | float: left;
645 | }
646 | }
647 | @media (min-width: 1080px) {
648 | .k-col.k-c-1-xl {
649 | width: calc(calc(100% - 20px) / 1);
650 | margin-right: 10px;
651 | margin-left: 10px;
652 | float: left;
653 | }
654 | }
655 | @media (min-width: 1080px) {
656 | .k-col.k-c-2-xl {
657 | width: calc(calc(100% - 40px) / 2);
658 | margin-right: 10px;
659 | margin-left: 10px;
660 | float: left;
661 | }
662 | }
663 | @media (min-width: 1080px) {
664 | .k-col.k-c-3-xl {
665 | width: calc(calc(100% - 60px) / 3);
666 | margin-right: 10px;
667 | margin-left: 10px;
668 | float: left;
669 | }
670 | }
671 | @media (min-width: 1080px) {
672 | .k-col.k-c-4-xl {
673 | width: calc(calc(100% - 80px) / 4);
674 | margin-right: 10px;
675 | margin-left: 10px;
676 | float: left;
677 | }
678 | }
679 | @media (min-width: 1080px) {
680 | .k-col.k-c-5-xl {
681 | width: calc(calc(100% - 100px) / 5);
682 | margin-right: 10px;
683 | margin-left: 10px;
684 | float: left;
685 | }
686 | }
687 | @media (min-width: 1080px) {
688 | .k-col.k-c-6-xl {
689 | width: calc(calc(100% - 120px) / 6);
690 | margin-right: 10px;
691 | margin-left: 10px;
692 | float: left;
693 | }
694 | }
695 | @media (min-width: 1080px) {
696 | .k-col.k-c-7-xl {
697 | width: calc(calc(100% - 140px) / 7);
698 | margin-right: 10px;
699 | margin-left: 10px;
700 | float: left;
701 | }
702 | }
703 | @media (min-width: 1080px) {
704 | .k-col.k-c-8-xl {
705 | width: calc(calc(100% - 160px) / 8);
706 | margin-right: 10px;
707 | margin-left: 10px;
708 | float: left;
709 | }
710 | }
711 | @media (min-width: 1080px) {
712 | .k-col.k-c-9-xl {
713 | width: calc(calc(100% - 180px) / 9);
714 | margin-right: 10px;
715 | margin-left: 10px;
716 | float: left;
717 | }
718 | }
719 | @media (min-width: 1080px) {
720 | .k-col.k-c-10-xl {
721 | width: calc(calc(100% - 200px) / 10);
722 | margin-right: 10px;
723 | margin-left: 10px;
724 | float: left;
725 | }
726 | }
727 | @media (min-width: 1080px) {
728 | .k-col.k-c-11-xl {
729 | width: calc(calc(100% - 220px) / 11);
730 | margin-right: 10px;
731 | margin-left: 10px;
732 | float: left;
733 | }
734 | }
735 | @media (min-width: 1080px) {
736 | .k-col.k-c-12-xl {
737 | width: calc(calc(100% - 240px) / 12);
738 | margin-right: 10px;
739 | margin-left: 10px;
740 | float: left;
741 | }
742 | }
743 | @media (min-width: 1080px) {
744 | .k-col.k-c-13-xl {
745 | width: calc(calc(100% - 260px) / 13);
746 | margin-right: 10px;
747 | margin-left: 10px;
748 | float: left;
749 | }
750 | }
751 | @media (min-width: 1080px) {
752 | .k-col.k-c-14-xl {
753 | width: calc(calc(100% - 280px) / 14);
754 | margin-right: 10px;
755 | margin-left: 10px;
756 | float: left;
757 | }
758 | }
759 | @media (min-width: 1080px) {
760 | .k-col.k-c-15-xl {
761 | width: calc(calc(100% - 300px) / 15);
762 | margin-right: 10px;
763 | margin-left: 10px;
764 | float: left;
765 | }
766 | }
767 | @media (min-width: 1080px) {
768 | .k-col.k-c-16-xl {
769 | width: calc(calc(100% - 320px) / 16);
770 | margin-right: 10px;
771 | margin-left: 10px;
772 | float: left;
773 | }
774 | }
775 |
--------------------------------------------------------------------------------
/public/graphs/css/notes.css:
--------------------------------------------------------------------------------
1 | #graph {
2 | height: 100vh;
3 | width: 100%;
4 | /* background-color: #222222; */
5 | background-color: #fa99f0;
6 | }
7 |
--------------------------------------------------------------------------------
/public/graphs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Graphs
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/public/graphs/js/notes.js:
--------------------------------------------------------------------------------
1 | var nodes = null;
2 | var edges = null;
3 | var network = null;
4 | var selectedNodeId = 1;
5 |
6 | var NOTES = ['C4', 'D4', 'E4', 'F4', 'G4', 'A4', 'B4'];
7 |
8 | var G = {
9 | '0': [0, 0, 2, 4],
10 | '1': [1, 1, 3, 5],
11 | '2': [2, 2, 4, 6],
12 | '3': [4],
13 | '4': [4, 0],
14 | '5': [0],
15 | '6': [1, 0],
16 | };
17 |
18 | var MC = new MarkovChain(G, NOTES, 0);
19 |
20 | // create an array with nodes
21 | function makeNodes(obj, labels) {
22 | var nodeStyle = {
23 | font: {
24 | color: '#000000',
25 | face: 'sans-serif',
26 | size: 20,
27 | },
28 | color: {
29 | highlight: {
30 | border: '#ccfa99',
31 | background: '#faf099',
32 | },
33 | },
34 | };
35 | const ids = Object.keys(obj).map(Number);
36 | return ids.map(id => {
37 | return {
38 | id,
39 | value: obj[id].length, // how many edges
40 | label: labels[id],
41 | ...nodeStyle,
42 | };
43 | });
44 | }
45 |
46 | function makeEdges(obj) {
47 | const edgeOptions = {
48 | arrows: {
49 | to: {
50 | enabled: true,
51 | },
52 | },
53 | color: {
54 | highlight: '#99f9fa',
55 | },
56 | };
57 |
58 | const ids = Object.keys(obj).map(Number);
59 | const edges = [];
60 |
61 | // Make matrix
62 | ids.forEach(id => {
63 | let values = {};
64 | obj[id].forEach(edge => {
65 | if (!values[edge]) {
66 | values[edge] = 1;
67 | } else {
68 | values[edge] += 1;
69 | }
70 | });
71 |
72 | Object.keys(values).forEach(k => {
73 | edges.push({
74 | from: id,
75 | to: Number(k),
76 | value: values[k],
77 | ...edgeOptions,
78 | });
79 | });
80 | });
81 |
82 | return edges;
83 | }
84 |
85 | function draw() {
86 | nodes = makeNodes(G, NOTES);
87 |
88 | edges = makeEdges(G);
89 |
90 | // create a network
91 | var container = document.getElementById('graph');
92 | var data = {
93 | nodes: nodes,
94 | edges: edges,
95 | };
96 | var options = {
97 | nodes: {
98 | shape: 'dot',
99 | size: 10,
100 | },
101 | };
102 | network = new vis.Network(container, data, options);
103 | }
104 |
105 | draw();
106 |
107 | network.fit(nodes.map(n => n.id));
108 |
109 | network.selectNodes([MC.peekID()]);
110 |
111 | setInterval(() => {
112 | selectedNodeId = MC.nextID();
113 | network.selectNodes([selectedNodeId]);
114 | }, 1000);
115 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | osc.js Web Socket Demo
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
OSC.js Visualizers
13 |
14 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/public/js/slides-setup.js:
--------------------------------------------------------------------------------
1 | var BLANK_PAGE_URL = '/public/blank.html';
2 | var slideshow = remark.create({
3 | sourceUrl: '/public/sqcr-demo/md/generative-hip-hop-slides.md',
4 | highlightStyle: 'monokai',
5 | touch: false,
6 | });
7 |
8 | function killIframes() {
9 | // Blank out all iframes
10 | const iframes = document.querySelectorAll('iframe');
11 | Array.from(iframes).forEach(el => {
12 | el.src = BLANK_PAGE_URL;
13 | });
14 | }
15 |
16 | slideshow.on('showSlide', function(slide) {
17 | if (!!window.DISABLE_IFRAMES) return;
18 | const {
19 | properties = { iframeURL: null, iframeSelector: null },
20 | properties: { iframeURL, iframeSelector },
21 | } = slide;
22 |
23 | if (iframeSelector) {
24 | const el = document.querySelector(iframeSelector);
25 | if (el) {
26 | el.src = iframeURL;
27 | }
28 | }
29 | // Slide is the slide being navigated to
30 | });
31 |
32 | slideshow.on('hideSlide', function(slide) {
33 | killIframes();
34 | });
35 |
36 | // Prevent duplicate iframes in presenter + child window mode
37 | if (window.opener) {
38 | window.opener.postMessage('mute', window.location.origin);
39 | console.log('Muting parent window by disabling iframes.');
40 | }
41 |
42 | window.addEventListener(
43 | 'message',
44 | e => {
45 | if (e && e.data === 'mute') {
46 | window.DISABLE_IFRAMES = true;
47 | console.log('Muting window and disabling iframes.');
48 | killIframes();
49 | }
50 | },
51 | false,
52 | );
53 |
--------------------------------------------------------------------------------
/public/matrix-16x8/example-sonic-pi-driver.rb:
--------------------------------------------------------------------------------
1 | #############################################################
2 | ### ###
3 | ### Made using SonicPi 3.1 ###
4 | ### ###
5 | ### by Omar Delarosa (https://omardelarosa.com) ###
6 | ### ###
7 | #############################################################
8 |
9 | use_bpm 70
10 | T = 4.0
11 |
12 | use_osc "192.168.1.7", 57121 # this synchronizes with the OSC server in the window. <-
13 |
14 | # State machine utility functions
15 | define :markov do |a, h| h[a].sample; end # Chooses the next state at random from hash
16 | define :g do |k| get[k]; end # simplified root note in scale getter
17 | define :s do |k, n| set k, n; end # simplified root note setter
18 | define :mnote do |key,chain| s key, (markov (g key), chain); g key; end
19 |
20 | # Pattern parsing
21 | define :ringify do |p| p.gsub(' ', '') .split('').map(&:to_i).ring; end
22 |
23 | # Melody builder
24 | define :make_melody do |len = 16, rng = 2|
25 | (1..len).map{|n| ((rng*-1)..rng).to_a.sample }.ring
26 | end
27 |
28 | # Initialize states
29 | set :k, 1
30 | set :b, 0
31 | set :s, 0
32 | set :y, 0
33 | set :v, 4
34 | set :h, 0
35 | set :l_lead, 0
36 | set :l_hats, 0
37 | set :l_kick, 0
38 | set :l_snare, 0
39 | set :l_vox, 1
40 |
41 | # Note playing abstraction
42 | define :pplay do |n, d = 0.1, m = 0.0, r = 0.0, syn = :fm|
43 | with_fx :reverb, mix: r do
44 | use_synth syn
45 | play n, release: d, sustain: 0.1
46 | end
47 | end
48 |
49 | # Scale
50 | sc_root = :F2
51 | sc_type = :major
52 | sc = scale(sc_root, sc_type)
53 |
54 | # Chords in scale -- chords are defined here.
55 | chords = (1..7).map {|n| chord_degree n, sc_root, sc_type }.ring
56 |
57 | # Samples
58 | SAMPLE_PATH = '~/Dropbox/Code/Music/SonicPi/Samples/Songs/Drake/'
59 |
60 | # Elaboration/Arrangement
61 | elaboration_complexities = (knit, 2, 4, 3, 2, 4, 2)
62 |
63 | # Levels
64 | L = {
65 | ppiano: [0.0, 0.35].ring,
66 | kick: [0.0, 0.75].ring,
67 | snare: [0.0, 0.75].ring,
68 | hats: [0.0, 1.5].ring,
69 | vox: [0.0, 5.0].ring
70 | }
71 |
72 | # Levels --- This is a markov chain controlling track/instrument levels.
73 | LV = {
74 | 0 => [0,0,1,1],
75 | 1 => [1,1,1,0]
76 | }
77 |
78 | # Tone family
79 | TONES = [:pulse, :fm, :pretty_bell]
80 |
81 | # Rhythm patterns -- kick drum patterns, each one is a single "state"
82 | p1 = [
83 | (ringify '4000 0000 0040 0000'),
84 | (ringify '4020 0000 4000 0000'),
85 | (ringify '4023 0010 4020 0000'),
86 | (ringify '4030 0020 4020 1000')
87 | ]
88 |
89 | # Kicks -- The markov chain controlling kick drum state transitions.
90 | B = {
91 | 0 => [0, 1, 0, 2],
92 | 1 => [0],
93 | 2 => [1, 0, 3],
94 | 3 => [0]
95 | }
96 |
97 | # Snare drum patterns. Each one is also a single state.
98 | p2 = [
99 | (ringify '0000 4000'),
100 | (ringify '0100 4000'),
101 | (ringify '1000 4000'),
102 | (ringify '0100 4100'),
103 | (ringify '0001 3001')
104 | ]
105 |
106 | # Snares - markov chain (but really just a hash representation of transitions)
107 | S = {
108 | 0 => [0, 0, 0, 0, 1, 2, 3],
109 | 1 => [0, 0, 1],
110 | 2 => [1, 0, 4, 3],
111 | 3 => [0],
112 | 4 => [0]
113 | }
114 |
115 | # Chords -- chord transitions
116 | K = {
117 | 1 => [7],
118 | 2 => [1],
119 | 7 => [2, 5],
120 | 5 => [1, 6],
121 | 6 => [2],
122 | 2 => [5]
123 | }
124 |
125 | melodies = (1..4).map{|n| make_melody(16,2)}.ring
126 |
127 | # Melodies
128 | Y = {
129 | 0 => [1],
130 | 1 => [0, 1, 2],
131 | 2 => [1, 2],
132 | 3 => [1]
133 | }
134 |
135 | # Vox
136 | V = {
137 | 0 => [0,0,1],
138 | 1 => [1,1,2],
139 | 2 => [2,2,3],
140 | 3 => [3,3,4],
141 | 4 => [4,4,0]
142 | }
143 |
144 | # Hats
145 | hats_durations = [
146 | (knit, T/16, 4),
147 | (knit, T/24, 6),
148 | (knit, T/16, 4),
149 | (knit, T/24, 6),
150 | (knit, T/16, 4),
151 | (knit, T/64, 8)
152 | ].ring
153 |
154 | H = {
155 | 0 => [1],
156 | 1 => [2],
157 | 2 => [3],
158 | 3 => [4],
159 | 4 => [5],
160 | 5 => [0],
161 | }
162 |
163 | define :pchord do |chr, d = T|
164 | with_fx :level, amp: 0.3 do
165 | ##| pplay chr[0], d, 0.8
166 | ##| pplay chr[1] + 24, d, 0.4
167 | ##| pplay chr[2], d, 0.8
168 | ##| pplay chr[3] + 12, d, 0.4
169 | end
170 | end
171 |
172 | live_loop :vox do
173 | s = mnote :v, V
174 | # Control vocal levels
175 | lv = mnote :l_vox, LV
176 | l = L[:vox][lv]
177 | with_fx :level, amp: l do
178 | with_fx :reverb, mix: 0.5 do
179 | sample SAMPLE_PATH, s
180 | end
181 | end
182 | sleep (T/1) * 2
183 | end
184 |
185 | live_loop :ppiano do
186 | chr = chords[mnote :k, K]
187 | pchord chr # Chord (left hand)
188 | complexity = elaboration_complexities.tick
189 | sleep T/(2**complexity)
190 | lv = mnote :l_lead, LV
191 | l = L[:ppiano][lv]
192 | t = TONES.sample
193 | melody = mnote :y, Y
194 | with_fx :echo, mix: 0.8 do
195 | (3*(complexity-1)-1).times do
196 | with_fx :level, amp: l do
197 | i = melodies[melody].tick
198 | pplay sc[i] + 24, (T/complexity-1), nil, nil, t
199 | 16.times do |n|
200 | # This controls the visualization synced to the lead.
201 | osc "/blink/#{(8 + i) % 8}/#{n}/0" if l > 0.0
202 | end
203 | sleep T/(2**complexity)
204 | end
205 | end
206 | end
207 |
208 | chr2 = chords[mnote :k, K]
209 | pchord chr2, T/4 # Chord
210 | with_fx :echo, mix: 0.8 do
211 | (1*(complexity-1)).times do
212 | with_fx :level, amp: l do
213 | i = melodies[melody].tick
214 | pplay sc[i] + 24, (T/complexity-1), nil, nil, t # Melody (right hand)
215 | 16.times do |n|
216 | osc "/blink/#{(8 + i) % 8}/#{n}/0" if l > 0.0
217 | end
218 | sleep T/(2**complexity)
219 | end
220 | end
221 | end
222 | end
223 |
224 |
225 | live_loop :kick do
226 | p = p1[mnote :b, B]
227 | lv = mnote :l_kick, LV
228 | l = L[:kick][lv]
229 | c = 0
230 | density (p.length / 2) do
231 | with_fx :level, amp: l do
232 | sample :bd_fat, amp: 3.5 if p.tick >= 1
233 | 8.times do |n|
234 | osc "/blink/#{n}/#{c}/1" if p.look >= 1 && l > 0.0
235 | end
236 | c+=1
237 | sleep 1
238 | end
239 | end
240 | end
241 |
242 | live_loop :hats do
243 | p = hats_durations[mnote :h, H]
244 | lv = mnote :l_hats, LV
245 | l = L[:hats][lv]
246 | c = 0
247 | density (p.length) do
248 | with_fx :level, amp: l do
249 | sample :elec_tick, amp: 1.5, decay: 0.1
250 | 8.times do |n|
251 | osc "/blink/#{n}/#{c}/2" if l > 0.0
252 | end
253 | c+=1
254 | sleep 1
255 | end
256 | end
257 | end
258 |
259 | # This controls the snares.
260 | live_loop :snare do
261 | # This mnote call fetches a pattern from the snare states.
262 | p = p2[mnote :s, S]
263 | # This mnote call fetches the level from the levels state for snare track.
264 | lv = mnote :l_snare, LV
265 | l = L[:snare][lv]
266 | c = 0
267 | density (p.length / 2) do
268 | with_fx :level, amp: l do
269 | sample :sn_dolf if p.tick >= 1
270 | 16.times do |n|
271 | osc "/blink/#{n}/#{c}/3" if p.look >= 1 && l > 0.0
272 | end
273 | c+=1
274 | sleep 1
275 | end
276 | end
277 | end
--------------------------------------------------------------------------------
/public/matrix-16x8/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Matrix 16x8 - osc.js demo
5 |
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 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
164 |
165 |
166 |
--------------------------------------------------------------------------------
/public/matrix-16x8/matrix-visualizer.js:
--------------------------------------------------------------------------------
1 | let oscPort = {};
2 |
3 | const handleMessage = (msg) => {
4 | console.log('message', msg);
5 | }
6 |
7 | const LightEvent = (data) => new CustomEvent('light', { detail: data });
8 |
9 | const elementMatrix = [];
10 |
11 | const mget = (mat, x, y) => {
12 | return mat[x] && mat[x][y] || undefined;
13 | }
14 |
15 | const MAX_COLS = 16;
16 | const MAX_ROWS = 8;
17 |
18 | const blink = (el, dur = 100, color) => {
19 | const colorClass = `colorize-${color}`;
20 | // TODO: add random color
21 | el.classList.add(colorClass);
22 |
23 | setTimeout(() => {
24 | el.classList.remove(colorClass);
25 | }, dur);
26 | }
27 |
28 | // For debugging purposes.
29 | const ticker = () => {
30 | let n = 0;
31 | let m = 0;
32 |
33 | return (e) => {
34 | const el = elementMatrix[n][m];
35 | blink(el);
36 | m++;
37 | if (m >= MAX_COLS) {
38 | m = 0;
39 | n++;
40 | }
41 |
42 | if (n >= MAX_ROWS) {
43 | n = 0;
44 | }
45 | };
46 | }
47 |
48 | const initOSC = () => {
49 | // Init container
50 | const $container = document.querySelector('.container');
51 |
52 | const $rows = document.querySelectorAll('.k-row');
53 |
54 | // TODO: make this more widely compatible and avoid .forEach
55 | $rows.forEach(($row) => {
56 | const rowRefs = [];
57 | $row.querySelectorAll('.k-col').forEach($cell => {
58 | rowRefs.push($cell);
59 | });
60 | elementMatrix.push(rowRefs);
61 | });
62 |
63 | $container.addEventListener('light', (e) => {
64 | const detail = e.detail || {};
65 | const { address = '', args = [] } = detail;
66 | const addressParts = address.split('/');
67 | if (addressParts[1] === 'blink') {
68 | const [,,m, n, color] = addressParts;
69 | const mNum = Number(m);
70 | const nNum = Number(n);
71 | const el = mget(elementMatrix,mNum,nNum);
72 | el && blink(el, 100, color);
73 | }
74 | });
75 |
76 | // Init port
77 | oscPort = new osc.WebSocketPort({
78 | url: "ws://localhost:8081"
79 | });
80 |
81 |
82 | // listen
83 | oscPort.on('message', (msg) => {
84 | // handleMessage(msg); // Debugging
85 |
86 | $container.dispatchEvent(LightEvent(msg));
87 | });
88 |
89 | // open port
90 | oscPort.open();
91 | };
92 |
93 | window.initOSC = initOSC;
94 |
--------------------------------------------------------------------------------
/public/matrix-16x8/styles.css:
--------------------------------------------------------------------------------
1 | div {
2 | min-height: 80px;
3 | }
4 |
5 | .container {
6 | margin-left: auto;
7 | margin-right: auto;
8 | }
9 |
10 | .k-row {
11 | margin-left: auto;
12 | margin-right: auto;
13 | max-width: 1600px;
14 | }
15 |
16 | .k-col {
17 | color: white;
18 | height: 80px;
19 | margin-bottom: 10px;
20 | margin-top: 10px;
21 | }
22 |
23 | .red-box {
24 | background-color: red;
25 | filter: blur(2px);
26 | }
27 |
28 | .blank-box {
29 | background-color: white;
30 | }
31 |
32 | .colorize {
33 | background-color: yellow;
34 | }
35 |
36 | .colorize-0 {
37 | background-color: red;
38 | /* filter: blur(2px); */
39 | }
40 |
41 | .colorize-1 {
42 | background-color: green;
43 | /* filter: blur(2px); */
44 | }
45 |
46 | .colorize-2 {
47 | background-color: yellow;
48 | /* filter: blur(2px); */
49 | }
50 |
51 | .colorize-3 {
52 | background-color: blue;
53 | /* filter: blur(2px); */
54 | }
55 |
56 | .colorize-4 {
57 | background-color: pink;
58 | /* filter: blur(2px); */
59 | }
60 |
61 | .colorize-1.colorize-3 {
62 | background-color: orange;
63 | }
64 |
65 | .colorize-2.colorize-3 {
66 | background-color: green;
67 | }
68 |
69 | .colorize-4.colorize-1 {
70 | background-color: teal;
71 | }
72 |
73 | .colorize-2.colorize-1 {
74 | background-color: orange;
75 | }
76 |
--------------------------------------------------------------------------------
/public/samples/BD.WAV:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/BD.WAV
--------------------------------------------------------------------------------
/public/samples/CB.WAV:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/CB.WAV
--------------------------------------------------------------------------------
/public/samples/CH.WAV:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/CH.WAV
--------------------------------------------------------------------------------
/public/samples/CL.WAV:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/CL.WAV
--------------------------------------------------------------------------------
/public/samples/CP.WAV:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/CP.WAV
--------------------------------------------------------------------------------
/public/samples/OH.WAV:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/OH.WAV
--------------------------------------------------------------------------------
/public/samples/SD.WAV:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/SD.WAV
--------------------------------------------------------------------------------
/public/samples/hotline-1-4s.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/hotline-1-4s.wav
--------------------------------------------------------------------------------
/public/samples/hotline-2-4s.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/hotline-2-4s.wav
--------------------------------------------------------------------------------
/public/samples/hotline-3-7s.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/hotline-3-7s.wav
--------------------------------------------------------------------------------
/public/samples/hotline-4-3.5s.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/hotline-4-3.5s.wav
--------------------------------------------------------------------------------
/public/samples/hotline-5-3.5s.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/hotline-5-3.5s.wav
--------------------------------------------------------------------------------
/public/samples/thug-01.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/thug-01.wav
--------------------------------------------------------------------------------
/public/samples/thug-02.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/thug-02.wav
--------------------------------------------------------------------------------
/public/samples/thug-03.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omardelarosa/markov-music-js/e7de4956ff0fcf81874b1cb9d6a44f5a9172e025/public/samples/thug-03.wav
--------------------------------------------------------------------------------
/public/sqcr-demo/buffers/init.js:
--------------------------------------------------------------------------------
1 | setTempo(60);
2 | sqcr.stop();
3 |
4 | // Global pulse counter
5 | pulse = 0;
6 |
7 | // Format pattern shorthand
8 | fmt = s =>
9 | s
10 | .replace(/\s/g, '')
11 | .split('')
12 | .map(Number);
13 | // Random element from arr
14 | _sample = arr => arr[parseInt(Math.random() * arr.length)];
15 |
16 | // Utility for generating infinite counters
17 | nextOf = max => {
18 | let i = 0;
19 | return () => {
20 | return ++i % max;
21 | };
22 | };
23 |
24 | beatFromTick = t => Math.floor((t / (T / 4)) % 16);
25 | tickToMS = t => SQCR.Transport.cl;
26 | expectedMS = ticks => sqcr.tickToMS() * ticks;
27 |
28 | next4 = nextOf(4);
29 |
30 | kicks = [
31 | fmt('4040 0000 0004 0000'),
32 | fmt('4000 0040 0040 0000'),
33 | // fmt('4020 0000 4000 0000'),
34 | // fmt('4020 0010 4020 0020'),
35 | // fmt('4030 0020 4020 1000')
36 | ];
37 |
38 | kick_pattern = _sample(kicks);
39 |
40 | hats = [
41 | [M / 16, 4],
42 | [M / 12, 3],
43 | [M / 24, 6],
44 | [M / 32, 4],
45 | [M / 48, 6],
46 | [M / 64, 8],
47 | ];
48 |
49 | // Create markov chain for hats
50 | MC_HATS = new MarkovChain(
51 | {
52 | '0': [0, 0, 0, 0, 0, 0, 1, 2, 3, 4],
53 | '1': [0, 0, 0, 3],
54 | '2': [0, 0, 0, 3],
55 | '3': [2, 5],
56 | '4': [2, 3, 4, 1],
57 | '5': [3, 2, 4, 2, 2],
58 | },
59 | hats,
60 | 0,
61 | );
62 |
63 | // Keeps track of hi-hat hits (or tick substate)
64 | h_counter = 0;
65 |
66 | snares = [
67 | fmt('0000 4000 0000 4000'),
68 | // fmt('0100 4000'),
69 | // fmt('1000 4000'),
70 | // fmt('0100 4100'),
71 | // fmt('0001 3011'),
72 | ];
73 |
74 | snares_pattern = _sample(snares);
75 |
76 | LETTERS = 'ABCDEFG';
77 |
78 | KEY = ['F4', 'major'];
79 |
80 | makeScale = note => Tonal.scale(KEY[1]).map(Tonal.transpose(note));
81 |
82 | noteParse = note => {
83 | const parts = note.split('');
84 | let letter;
85 | let isSharp = false;
86 | let oct = 0;
87 | // Has flat
88 | if (parts.length === 3) {
89 | let idx = LETTERS.indexOf(parts[0]);
90 | if (idx === -1) throw new Error('Invalid note: ' + note);
91 | else if (idx === 0) {
92 | idx = LETTERS.length - 1;
93 | } else {
94 | idx = idx - 1;
95 | }
96 | letter = LETTERS[idx];
97 | isSharp = true;
98 | oct = parseInt(parts[2]);
99 | } else {
100 | letter = parts[0];
101 | oct = parseInt(parts[1]);
102 | }
103 | return {
104 | note: letter + (isSharp ? '#' : ''),
105 | oct,
106 | };
107 | };
108 |
109 | // Make an array of notes
110 | scale = [
111 | ...makeScale('F3'),
112 | ...makeScale('F4'),
113 | ...makeScale('F5'),
114 | ...makeScale('F6'),
115 | ];
116 | chords = [0, 3, 4, 3, 2];
117 | chord = 0;
118 | notes = [0, 2, 4, 6];
119 |
120 | // Get MIDI outputs
121 | NOTE_KICK = 'A0';
122 | NOTE_SNARE = 'A1';
123 | NOTE_HAT = 'A2';
124 | NOTE_CLAP = 'B1';
125 |
126 | DRAKE = ['C2', 'D2', 'E2', 'F2', 'G2'];
127 | THUG = ['C3', 'D3', 'E4'];
128 |
129 | playInst = (inst, note, dur = 50) => {
130 | let timer;
131 | try {
132 | inst.triggerAttack(note);
133 | timer = setTimeout(() => {
134 | inst.triggerRelease(note);
135 | }, dur);
136 | } catch (e) {
137 | clearTimeout(timer);
138 | console.log('Instrument error!', e.message);
139 | }
140 | };
141 |
--------------------------------------------------------------------------------
/public/sqcr-demo/buffers/loops.js:
--------------------------------------------------------------------------------
1 | // Edit this file while running the server to update loops in real time
2 |
3 | colorLoopMapping = {
4 | synth: 3,
5 | leadSynth: 1,
6 | kicks: 2,
7 | hats: 0,
8 | snares: 4,
9 | };
10 |
11 | loop('synth', async ctx => {
12 | // // Update chord state
13 | chord = chords[next4()];
14 | const chr = notes.map(n => scale[n + chord]);
15 | chr.forEach(n => {
16 | const dur = 2 * 1000;
17 | playInst(synth, n, dur);
18 | const scaleNote = scale.indexOf(n) % 8;
19 | // Visualizer.blink(
20 | // `/blink/${scaleNote}/${pulse}/${colorLoopMapping[ctx.name]}/${dur}`,
21 | // );
22 | for (let i = 0; i < 16; i++) {
23 | Visualizer.blink(
24 | `/blink/${scaleNote}/${i}/${colorLoopMapping[ctx.name]}/${dur}`,
25 | );
26 | }
27 | });
28 |
29 | ctx.sleep((M / 1) * 2);
30 | });
31 |
32 | since = Date.now();
33 |
34 | loop('leadSynth', async ctx => {
35 | const pulse = beatFromTick(ctx.tick);
36 | const n = _sample(
37 | notes.map(n => {
38 | return scale[n + chord];
39 | }),
40 | );
41 | const now = Date.now();
42 | console.log('since', now - since);
43 | since = now;
44 | const scaleNote = scale.indexOf(n) % 8;
45 | Visualizer.blink(
46 | `/blink/${scaleNote}/${pulse}/${colorLoopMapping[ctx.name]}/100`,
47 | );
48 | // console.log('N', scale.indexOf(n));
49 | playInst(leadSynth, n, 100);
50 | ctx.sleep(T / 4);
51 | });
52 |
53 | loop('blinker', async ctx => {
54 | const pulse = beatFromTick(ctx.tick);
55 | for (let i = 0; i < 8; i++) {
56 | Visualizer.blink(`/blink/${i}/${pulse}/0/${sqcr.tickToMS() * (T / 4)}`);
57 | }
58 | ctx.sleep(T / 4);
59 | });
60 |
61 | loop('kicks', async ctx => {
62 | const pulse = beatFromTick(ctx.tick);
63 | // Switch pattern on the 0
64 | if (pulse === 0) kick_pattern = _sample(kicks);
65 | if (!kick_pattern[pulse]) return ctx.sleep(T / 4);
66 |
67 | // Play kick beat
68 | playInst(sampler, NOTE_KICK);
69 |
70 | ctx.sleep(T / 4);
71 | });
72 |
73 | loop('hats', async ctx => {
74 | hats_pattern = hats[MC.get('HATS')];
75 | max = hats_pattern[1];
76 | t = hats_pattern[0];
77 |
78 | playInst(sampler, NOTE_HAT);
79 |
80 | // Visualizer
81 | for (let i = 0; i < 8; i++) {
82 | Visualizer.blink(`/blink/${i}/${h_counter}/2/${sqcr.tickToMS() * t}`);
83 | }
84 |
85 | if (h_counter >= max - 1) {
86 | MC.set('HATS');
87 | h_counter = 0;
88 | } else {
89 | h_counter++;
90 | }
91 |
92 | ctx.sleep(t);
93 | });
94 |
95 | loop('snares', async ctx => {
96 | const pulse = beatFromTick(ctx.tick);
97 | // // Switch pattern on the 0
98 | if (pulse === 0) snares_pattern = _sample(snares);
99 | if (!snares_pattern[pulse]) return ctx.sleep(T / 4);
100 | playInst(sampler, NOTE_CLAP);
101 | ctx.sleep(T / 4);
102 | });
103 |
--------------------------------------------------------------------------------
/public/sqcr-demo/buffers/synths.js:
--------------------------------------------------------------------------------
1 | // Tone.js stuff
2 | freeverb = new Tone.Freeverb({
3 | wet: 0.8,
4 | decay: '8n',
5 | }).toMaster();
6 |
7 | reverb = new Tone.Reverb({
8 | wet: 0.2,
9 | decay: '8n',
10 | }).toMaster();
11 |
12 | delay = new Tone.FeedbackDelay(0.1);
13 |
14 | tremolo = new Tone.Tremolo(9, 0.75).toMaster().start();
15 |
16 | feedbackDelay = new Tone.PingPongDelay({
17 | delayTime: '8n',
18 | feedback: 0.6,
19 | wet: 0.2,
20 | }).toMaster();
21 |
22 | synth = new Tone.PolySynth(6, Tone.Synth, {
23 | volume: 0.5,
24 | oscillator: {
25 | partials: [0, 2, 3, 4],
26 | },
27 | })
28 | .set({
29 | filter: {
30 | type: 'highpass',
31 | },
32 | envelope: {
33 | attack: 0.1,
34 | },
35 | })
36 | // .chain(tremolo, freeverb)
37 | .toMaster();
38 |
39 | leadSynth = new Tone.PolySynth(6, Tone.Synth, {
40 | oscillator: {
41 | partials: [0, 2, 3, 4],
42 | },
43 | })
44 | .set({
45 | filter: {
46 | type: 'highpass',
47 | },
48 | envelope: {
49 | attack: 0.1,
50 | },
51 | })
52 | // .chain(delay, freeverb)
53 | // .connect(reverb)
54 | // .connect(feedbackDelay)
55 | .toMaster();
56 |
57 | sampler = new Tone.Sampler(
58 | {
59 | [NOTE_KICK]: 'BD.WAV', // Kick
60 | [NOTE_SNARE]: 'SD.WAV', // Snare
61 | [NOTE_HAT]: 'CH.WAV', // Closed Hats
62 | [NOTE_CLAP]: 'CP.WAV', // Clap
63 | [DRAKE[0]]: 'hotline-1-4s.wav',
64 | [DRAKE[1]]: 'hotline-2-4s.wav',
65 | [DRAKE[2]]: 'hotline-3-7s.wav',
66 | [DRAKE[3]]: 'hotline-4-3.5s.wav',
67 | [DRAKE[4]]: 'hotline-5-3.5s.wav',
68 | [THUG[0]]: 'thug-01.wav',
69 | [THUG[1]]: 'thug-02.wav',
70 | [THUG[2]]: 'thug-03.wav',
71 | },
72 | {
73 | release: 1,
74 | baseUrl: '/public/samples/',
75 | },
76 | )
77 | .connect(reverb)
78 | .toMaster();
79 |
--------------------------------------------------------------------------------
/public/sqcr-demo/config/matrix.json:
--------------------------------------------------------------------------------
1 | {
2 | "libs": [
3 | "/node_modules/webmidi/webmidi.min.js",
4 | "/node_modules/osc/dist/osc-browser.js",
5 | "/node_modules/tonal/build/transpiled.js",
6 | "/node_modules/tone/build/Tone.min.js",
7 | "/node_modules/sqcr/lib/browser.js",
8 | "/public/sqcr-demo/sqcr-setup.js",
9 | "/public/sqcr-demo/buffers/init.js",
10 | "/public/sqcr-demo/buffers/synths.js",
11 | "/public/sqcr-demo/buffers/loops.js",
12 | "/public/sqcr-demo/visualizer.js"
13 | ],
14 | "rendererPath": "public/sqcr-demo/renderers/matrix-renderer.js"
15 | }
16 |
--------------------------------------------------------------------------------
/public/sqcr-demo/config/presentation.json:
--------------------------------------------------------------------------------
1 | {
2 | "libs": [
3 | "/node_modules/webmidi/webmidi.min.js",
4 | "/node_modules/osc/dist/osc-browser.js",
5 | "/node_modules/tonal/build/transpiled.js",
6 | "/node_modules/tone/build/Tone.min.js",
7 | "/node_modules/sqcr/lib/standalone.js",
8 | "/public/sqcr-demo/sqcr-setup.js",
9 | "/public/sqcr-demo/buffers/init.js",
10 | "/public/sqcr-demo/buffers/synths.js",
11 | "/public/sqcr-demo/buffers/loops.js",
12 | "/public/sqcr-demo/visualizer.js"
13 | ],
14 | "rendererPath": "public/sqcr-demo/renderers/slider.js",
15 | "locals": {
16 | "MARKDOWN_PATH": "/public/sqcr-demo/md/generative-hip-hop-slides.md"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/public/sqcr-demo/css/slides.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Arimo:400,400i,700,700i|Roboto+Mono:400,400i,700,700i');
2 |
3 | /**
4 | * Color Pallette:
5 | * 1 - #ccfa99
6 | * 2 - #faf099
7 | * 3 - #99f0fa
8 | * 4 - #fa99f0
9 | * 5 - #cc99fa
10 | *
11 | */
12 |
13 | :root {
14 | /* --main-bg-color: #000000; */
15 | --main-bg-color: #fa99f0;
16 | /* --main-text-color: #ffffff; */
17 | --main-text-color: #000000;
18 | --code-bg-color: #222222;
19 | --code-text-color: #ffffff;
20 | }
21 |
22 | body {
23 | font-family: 'Arimo', sans-serif;
24 | color: var(--main-text-color);
25 | background-color: var(--main-bg-color);
26 | }
27 |
28 | .remark-container,
29 | .remark-slide,
30 | .remark-slide-content {
31 | background-color: var(--main-bg-color);
32 | }
33 |
34 | .remark-slide-scaler {
35 | box-shadow: unset;
36 | -webkit-box-shadow: unset;
37 | }
38 |
39 | h1,
40 | h2,
41 | h3 {
42 | font-family: 'Arimo', sans-serif;
43 | }
44 | .remark-code,
45 | .remark-inline-code {
46 | font-family: 'Roboto Mono', monospace;
47 | background-color: var(--code-bg-color);
48 | color: var(--code-text-color);
49 | }
50 |
--------------------------------------------------------------------------------
/public/sqcr-demo/html/808.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Untitled - osc.js demo
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
31 |
32 |
33 |
34 |

35 |
36 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/public/sqcr-demo/html/akai.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Untitled - osc.js demo
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
32 |
33 |
34 |
35 |

36 |
37 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/public/sqcr-demo/html/beats-graph.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Graphs
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/public/sqcr-demo/html/chords-graph.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Graphs
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/public/sqcr-demo/html/matrix-16x8.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Untitled - osc.js demo
5 |
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 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
175 |
176 |
177 |
178 |
179 |
--------------------------------------------------------------------------------
/public/sqcr-demo/html/notes-graph.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Graphs
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/public/sqcr-demo/html/random-tones.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Untitled - osc.js demo
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
19 |
20 |
21 |
22 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/public/sqcr-demo/html/scale-tones.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Untitled - osc.js demo
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
19 |
20 |
21 |
22 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/public/sqcr-demo/js/chords-graph-synth.js:
--------------------------------------------------------------------------------
1 | var nodes = null;
2 | var edges = null;
3 | var network = null;
4 | var selectedNodeId = 1;
5 |
6 | var note = null;
7 | var duration = 2000;
8 |
9 | var CHORDS = [
10 | 'C Major',
11 | 'D minor',
12 | 'E minor',
13 | 'F major',
14 | 'G major',
15 | 'A minor',
16 | 'B diminished',
17 | ];
18 |
19 | var NOTES = [
20 | 'C4',
21 | 'D4',
22 | 'E4',
23 | 'F4',
24 | 'G4',
25 | 'A4',
26 | 'B4',
27 | 'C4',
28 | 'D4',
29 | 'E4',
30 | 'F4',
31 | 'G4',
32 | 'A4',
33 | 'B4',
34 | ];
35 |
36 | function rand() {
37 | return CHORDS[Math.round(Math.random() * (CHORDS.length - 1))];
38 | }
39 |
40 | var synth = new Tone.PolySynth(3, Tone.Synth, {
41 | oscillator: {
42 | type: 'amtriangle',
43 | harmonicity: 0.5,
44 | modulationType: 'sine',
45 | },
46 | envelope: {
47 | attackCurve: 'exponential',
48 | attack: 0.05,
49 | decay: 0.2,
50 | sustain: 0.2,
51 | release: 1.5,
52 | },
53 | portamento: 0.05,
54 | }).toMaster();
55 |
56 | var G = {
57 | '0': [3, 3, 3, 5],
58 | '1': [2, 5],
59 | '2': [3],
60 | '3': [4, 4, 4, 1, 1],
61 | '4': [0, 0, 0, 5],
62 | '5': [1, 6],
63 | '6': [4],
64 | };
65 |
66 | var MC = new MarkovChain(G, CHORDS, 0);
67 |
68 | // create an array with nodes
69 | function makeNodes(obj, labels) {
70 | var nodeStyle = {
71 | font: {
72 | color: '#000000',
73 | face: 'sans-serif',
74 | size: 20,
75 | },
76 | color: {
77 | highlight: {
78 | border: '#ccfa99',
79 | background: '#faf099',
80 | },
81 | },
82 | };
83 | const ids = Object.keys(obj).map(Number);
84 | return ids.map(id => {
85 | return {
86 | id,
87 | value: obj[id].length, // how many edges
88 | label: labels[id],
89 | ...nodeStyle,
90 | };
91 | });
92 | }
93 |
94 | function makeEdges(obj) {
95 | const edgeOptions = {
96 | arrows: {
97 | to: {
98 | enabled: true,
99 | },
100 | },
101 | color: {
102 | highlight: '#99f9fa',
103 | },
104 | };
105 |
106 | const ids = Object.keys(obj).map(Number);
107 | const edges = [];
108 |
109 | // Make matrix
110 | ids.forEach(id => {
111 | let values = {};
112 | obj[id].forEach(edge => {
113 | if (!values[edge]) {
114 | values[edge] = 1;
115 | } else {
116 | values[edge] += 1;
117 | }
118 | });
119 |
120 | Object.keys(values).forEach(k => {
121 | edges.push({
122 | from: id,
123 | to: Number(k),
124 | value: values[k],
125 | ...edgeOptions,
126 | });
127 | });
128 | });
129 |
130 | return edges;
131 | }
132 |
133 | function draw() {
134 | nodes = makeNodes(G, CHORDS);
135 |
136 | edges = makeEdges(G);
137 |
138 | // create a network
139 | var container = document.getElementById('graph');
140 | var data = {
141 | nodes: nodes,
142 | edges: edges,
143 | };
144 | var options = {
145 | nodes: {
146 | shape: 'dot',
147 | size: 10,
148 | },
149 | };
150 | network = new vis.Network(container, data, options);
151 | }
152 |
153 | draw();
154 |
155 | network.fit(nodes.map(n => n.id));
156 |
157 | network.selectNodes([MC.peekID()]);
158 |
159 | setInterval(() => {
160 | selectedNodeId = MC.nextID();
161 | network.selectNodes([selectedNodeId]);
162 | note = NOTES[selectedNodeId];
163 | note2 = NOTES[selectedNodeId + 2];
164 | note3 = NOTES[selectedNodeId + 4];
165 | const notes = [note, note2, note3];
166 | console.log('NOTES', notes, duration);
167 | synth.triggerAttackRelease(notes, duration);
168 | }, duration);
169 |
--------------------------------------------------------------------------------
/public/sqcr-demo/js/hats-graph-synth.js:
--------------------------------------------------------------------------------
1 | var nodes = null;
2 | var edges = null;
3 | var network = null;
4 | var selectedNodeId = 1;
5 |
6 | var note = null;
7 |
8 | var HATS = [
9 | [M / 16, 4],
10 | [M / 12, 3],
11 | [M / 24, 6],
12 | [M / 32, 4],
13 | [M / 48, 6],
14 | [M / 64, 8],
15 | ];
16 |
17 | var HATS_STR = ['1/16', '1/12', '1/24', '1/32', '1/48', '1/64'];
18 |
19 | var G = {
20 | '0': [0, 0, 0, 0, 0, 0, 1, 2, 3, 4],
21 | '1': [0, 0, 0, 3],
22 | '2': [0, 0, 0, 3],
23 | '3': [2, 5],
24 | '4': [2, 3, 4, 1],
25 | '5': [3, 2, 4, 2, 2],
26 | };
27 |
28 | var synth = new Tone.PolySynth(3, Tone.Synth, {
29 | oscillator: {
30 | type: 'amtriangle',
31 | harmonicity: 0.5,
32 | modulationType: 'sine',
33 | },
34 | envelope: {
35 | attackCurve: 'exponential',
36 | attack: 0.05,
37 | decay: 0.2,
38 | sustain: 0.2,
39 | release: 1.5,
40 | },
41 | portamento: 0.05,
42 | }).toMaster();
43 |
44 | var MC = new MarkovChain(G, HATS, 0);
45 |
46 | // create an array with nodes
47 | function makeNodes(obj, labels) {
48 | var nodeStyle = {
49 | font: {
50 | color: '#000000',
51 | face: 'sans-serif',
52 | size: 20,
53 | },
54 | color: {
55 | highlight: {
56 | border: '#ccfa99',
57 | background: '#faf099',
58 | },
59 | },
60 | };
61 | const ids = Object.keys(obj).map(Number);
62 | return ids.map(id => {
63 | return {
64 | id,
65 | value: obj[id].length, // how many edges
66 | label: labels[id],
67 | ...nodeStyle,
68 | };
69 | });
70 | }
71 |
72 | function makeEdges(obj) {
73 | const edgeOptions = {
74 | arrows: {
75 | to: {
76 | enabled: true,
77 | },
78 | },
79 | color: {
80 | highlight: '#99f9fa',
81 | },
82 | };
83 |
84 | const ids = Object.keys(obj).map(Number);
85 | const edges = [];
86 |
87 | // Make matrix
88 | ids.forEach(id => {
89 | let values = {};
90 | obj[id].forEach(edge => {
91 | if (!values[edge]) {
92 | values[edge] = 1;
93 | } else {
94 | values[edge] += 1;
95 | }
96 | });
97 |
98 | Object.keys(values).forEach(k => {
99 | edges.push({
100 | from: id,
101 | to: Number(k),
102 | value: values[k],
103 | ...edgeOptions,
104 | });
105 | });
106 | });
107 |
108 | return edges;
109 | }
110 |
111 | function draw() {
112 | nodes = makeNodes(G, HATS_STR);
113 |
114 | edges = makeEdges(G);
115 |
116 | // create a network
117 | var container = document.getElementById('graph');
118 | var data = {
119 | nodes: nodes,
120 | edges: edges,
121 | };
122 | var options = {
123 | nodes: {
124 | shape: 'dot',
125 | size: 10,
126 | },
127 | };
128 | network = new vis.Network(container, data, options);
129 | }
130 |
131 | draw();
132 |
133 | network.fit(nodes.map(n => n.id));
134 |
135 | network.selectNodes([MC.peekID()]);
136 |
137 | // SQCR Stuff
138 | setTempo(60);
139 |
140 | // Get MIDI outputs
141 | NOTE_HAT = 'A2';
142 |
143 | sampler = new Tone.Sampler(
144 | {
145 | [NOTE_HAT]: 'CH.WAV', // Closed Hats
146 | },
147 | {
148 | release: 1,
149 | baseUrl: '/public/samples/',
150 | },
151 | ).toMaster();
152 |
153 | h_counter = 0;
154 |
155 | playInst = (inst, note, dur = 50) => {
156 | let timer;
157 | try {
158 | inst.triggerAttack(note);
159 | } catch (e) {
160 | console.log('Instrument error!', e.message);
161 | }
162 | };
163 |
164 | hats = [
165 | [M / 16, 4],
166 | [M / 12, 3],
167 | [M / 24, 6],
168 | [M / 32, 4],
169 | [M / 48, 6],
170 | [M / 64, 8],
171 | ];
172 |
173 | loop('hats', async ctx => {
174 | hats_pattern = hats[MC.peekID()];
175 | max = hats_pattern[1];
176 | t = hats_pattern[0];
177 |
178 | playInst(sampler, NOTE_HAT);
179 |
180 | if (h_counter >= max - 1) {
181 | const nid = MC.nextID();
182 | network.selectNodes([nid]);
183 | h_counter = 0;
184 | } else {
185 | h_counter++;
186 | }
187 |
188 | ctx.sleep(t);
189 | });
190 |
--------------------------------------------------------------------------------
/public/sqcr-demo/js/matrix-16x8-init.js:
--------------------------------------------------------------------------------
1 | setTempo(60);
2 |
3 | // Global pulse counter
4 | pulse = 0;
5 |
6 | // Format pattern shorthand
7 | fmt = s =>
8 | s
9 | .replace(/\s/g, '')
10 | .split('')
11 | .map(Number);
12 | // Random element from arr
13 | _sample = arr => arr[parseInt(Math.random() * arr.length)];
14 |
15 | // Utility for generating infinite counters
16 | nextOf = max => {
17 | let i = 0;
18 | return () => {
19 | return ++i % max;
20 | };
21 | };
22 |
23 | beatFromTick = t => Math.floor((t / (T / 4)) % 16);
24 | tickToMS = t => SQCR.Transport.cl;
25 | expectedMS = ticks => sqcr.tickToMS() * ticks;
26 |
27 | next4 = nextOf(4);
28 |
29 | LOOPS = ['synth', 'leadSynth', 'kicks', 'snares', 'hats', 'vocals'];
30 | LEVELS = {
31 | synth: 1,
32 | leadSynth: 1,
33 | kicks: 1,
34 | snares: 0,
35 | hats: 1,
36 | vocals: 0,
37 | };
38 |
39 | MC_LEVELS = new MarkovChain(
40 | {
41 | '1': [1, 1, 1, 0, 0],
42 | '0': [0, 0, 1, 1, 1],
43 | },
44 | [1, 0],
45 | 1,
46 | );
47 |
48 | kicks = [
49 | fmt('4000 0000 0040 0000'),
50 | fmt('4020 0000 4000 0000'),
51 | fmt('4023 0010 4020 0000'),
52 | fmt('4030 0020 4020 1000'),
53 | ];
54 |
55 | MC_KICKS = new MarkovChain(
56 | {
57 | '0': [0, 1, 0, 2],
58 | '1': [0],
59 | '2': [1, 0, 3],
60 | '3': [0],
61 | },
62 | kicks,
63 | 0,
64 | );
65 |
66 | hats = [
67 | [M / 16, 4],
68 | [M / 12, 3],
69 | [M / 24, 6],
70 | [M / 32, 4],
71 | [M / 48, 6],
72 | [M / 64, 8],
73 | ];
74 |
75 | // Create markov chain for hats
76 | MC_HATS = new MarkovChain(
77 | {
78 | '0': [0, 0, 0, 0, 0, 0, 1, 2, 3, 4],
79 | '1': [0, 0, 0, 3],
80 | '2': [0, 0, 0, 3],
81 | '3': [2, 5],
82 | '4': [2, 3, 4, 1],
83 | '5': [3, 2, 4, 2, 2],
84 | },
85 | hats,
86 | 0,
87 | );
88 |
89 | // Keeps track of hi-hat hits (or tick substate)
90 | h_counter = 0;
91 |
92 | snares = [
93 | fmt('0000 4000'),
94 | fmt('0100 4000'),
95 | fmt('1000 4000'),
96 | fmt('0100 4100'),
97 | fmt('0001 3001'),
98 | ];
99 |
100 | MC_SNARES = new MarkovChain(
101 | {
102 | '0': [0, 0, 0, 0, 1, 2, 3],
103 | '1': [0, 0, 1],
104 | '2': [1, 0, 4, 3],
105 | '3': [0],
106 | '4': [0],
107 | },
108 | snares,
109 | 0,
110 | );
111 |
112 | LETTERS = 'ABCDEFG';
113 |
114 | KEY = ['F4', 'major'];
115 |
116 | makeScale = note => Tonal.scale(KEY[1]).map(Tonal.transpose(note));
117 |
118 | // Make an array of notes
119 | scale = [
120 | ...makeScale('F3'),
121 | ...makeScale('F4'),
122 | ...makeScale('F5'),
123 | ...makeScale('F6'),
124 | ];
125 |
126 | chordNotesOf = deg => [
127 | scale[deg],
128 | scale[deg + 2],
129 | scale[deg + 4],
130 | scale[deg + 6],
131 | ];
132 |
133 | chords = [0, 1, 2, 3, 4, 5, 6, 7, 8];
134 |
135 | MC_CHORDS = new MarkovChain(
136 | {
137 | '0': [4],
138 | '1': [7],
139 | '2': [1],
140 | '3': [2, 2, 4, 4, 0],
141 | '4': [3, 3, 6, 6, 0],
142 | '7': [2, 5],
143 | '5': [1, 6],
144 | '6': [2],
145 | },
146 | chords,
147 | 0,
148 | );
149 |
150 | melody = [];
151 |
152 | for (let i = 0; i < 16; i++) {
153 | melody.push(Math.round(Math.random() * 16) % 8);
154 | }
155 |
156 | console.log('melody', melody);
157 |
158 | notes = [0, 2, 4, 6];
159 |
160 | // Get MIDI outputs
161 | NOTE_KICK = 'A0';
162 | NOTE_SNARE = 'A1';
163 | NOTE_HAT = 'A2';
164 | NOTE_CLAP = 'B1';
165 |
166 | DRAKE = ['C2', 'D2', 'E2', 'F2', 'G2'];
167 | THUG = ['C3', 'D3', 'E4'];
168 |
169 | playInst = (inst, note, dur = 50) => {
170 | let timer;
171 | try {
172 | inst.triggerAttack(note);
173 | timer = setTimeout(() => {
174 | inst.triggerRelease(note);
175 | }, dur);
176 | } catch (e) {
177 | clearTimeout(timer);
178 | console.log('Instrument error!', e.message);
179 | }
180 | };
181 |
--------------------------------------------------------------------------------
/public/sqcr-demo/js/matrix-16x8-synths.js:
--------------------------------------------------------------------------------
1 | // Tone.js stuff
2 | freeverb = new Tone.Freeverb({
3 | wet: 0.8,
4 | decay: '8n',
5 | }).toMaster();
6 |
7 | reverb = new Tone.Reverb({
8 | wet: 0.2,
9 | decay: '8n',
10 | }).toMaster();
11 |
12 | delay = new Tone.FeedbackDelay(0.1);
13 |
14 | tremolo = new Tone.Tremolo(9, 0.75).toMaster().start();
15 |
16 | feedbackDelay = new Tone.PingPongDelay({
17 | delayTime: '8n',
18 | feedback: 0.6,
19 | wet: 0.2,
20 | }).toMaster();
21 |
22 | synth = new Tone.PolySynth(6, Tone.Synth, {
23 | volume: 1,
24 | oscillator: {
25 | partials: [0, 2, 3, 4],
26 | },
27 | })
28 | .set({
29 | filter: {
30 | type: 'highpass',
31 | },
32 | envelope: {
33 | attack: 0.1,
34 | },
35 | })
36 | // .chain(tremolo, freeverb)
37 | .toMaster();
38 |
39 | leadSynth = new Tone.PolySynth(6, Tone.Synth, {
40 | oscillator: {
41 | partials: [0, 2, 3, 4],
42 | },
43 | })
44 | .set({
45 | filter: {
46 | type: 'highpass',
47 | },
48 | envelope: {
49 | attack: 0.1,
50 | },
51 | })
52 | // .chain(delay, freeverb)
53 | // .connect(reverb)
54 | // .connect(feedbackDelay)
55 | .toMaster();
56 |
57 | sampler = new Tone.Sampler(
58 | {
59 | [NOTE_KICK]: 'BD.WAV', // Kick
60 | [NOTE_SNARE]: 'SD.WAV', // Snare
61 | [NOTE_HAT]: 'CH.WAV', // Closed Hats
62 | [NOTE_CLAP]: 'CP.WAV', // Clap
63 | [DRAKE[0]]: 'hotline-1-4s.wav',
64 | [DRAKE[1]]: 'hotline-2-4s.wav',
65 | [DRAKE[2]]: 'hotline-3-7s.wav',
66 | [DRAKE[3]]: 'hotline-4-3.5s.wav',
67 | [DRAKE[4]]: 'hotline-5-3.5s.wav',
68 | [THUG[0]]: 'thug-01.wav',
69 | [THUG[1]]: 'thug-02.wav',
70 | [THUG[2]]: 'thug-03.wav',
71 | },
72 | {
73 | release: 1,
74 | baseUrl: '/public/samples/',
75 | },
76 | )
77 | .connect(reverb)
78 | .toMaster();
79 |
--------------------------------------------------------------------------------
/public/sqcr-demo/js/matrix-16x8.js:
--------------------------------------------------------------------------------
1 | colorLoopMapping = {
2 | synth: 3,
3 | leadSynth: 1,
4 | kicks: 2,
5 | hats: 0,
6 | snares: 4,
7 | };
8 |
9 | loop('levels', async ctx => {
10 | LOOPS.forEach(l => {
11 | // Update levels of each track
12 | LEVELS[l] = MC_LEVELS.next();
13 | });
14 |
15 | // Every measure
16 | ctx.sleep(M * 4);
17 | });
18 |
19 | loop('synth', async ctx => {
20 | // Update chord state
21 | chordId = MC_CHORDS.next();
22 | chordNotes = chordNotesOf(chordId);
23 |
24 | chordNotes.forEach(n => {
25 | const dur = 4 * 1000;
26 | playInst(synth, n, dur);
27 | const scaleNote = scale.indexOf(n) % 8;
28 | // Visualizer.blink(
29 | // `/blink/${scaleNote}/${pulse}/${colorLoopMapping[ctx.name]}/${dur}`,
30 | // );
31 | for (let i = 0; i < 16; i++) {
32 | Visualizer.blink(
33 | `/blink/${scaleNote}/${i}/${colorLoopMapping[ctx.name]}/${dur}`,
34 | );
35 | }
36 | });
37 |
38 | ctx.sleep((M / 1) * 1);
39 | });
40 |
41 | since = Date.now();
42 |
43 | loop('leadSynth', async ctx => {
44 | const pulse = beatFromTick(ctx.tick);
45 | const chordOffset = MC_CHORDS.peekID();
46 | const mNote = melody[pulse] + chordOffset;
47 | const scaleNote = scale[mNote]; // octave scaled
48 | if (LEVELS[ctx.name]) {
49 | Visualizer.blink(
50 | `/blink/${mNote % 8}/${pulse}/${colorLoopMapping[ctx.name]}/100`,
51 | );
52 | playInst(leadSynth, scaleNote, 100);
53 | ctx.sleep(T / 4);
54 | } else {
55 | playInst(leadSynth, scaleNote, 100);
56 | ctx.sleep(T / 2);
57 | }
58 | });
59 |
60 | loop('blinker', async ctx => {
61 | const pulse = beatFromTick(ctx.tick);
62 | for (let i = 0; i < 8; i++) {
63 | Visualizer.blink(`/blink/${i}/${pulse}/0/${sqcr.tickToMS() * (T / 4)}`);
64 | }
65 | ctx.sleep(T / 4);
66 | });
67 |
68 | loop('kicks', async ctx => {
69 | const pulse = beatFromTick(ctx.tick);
70 | // Switch pattern on the 0
71 | if (pulse === 0) MC_KICKS.next();
72 | if (!MC_KICKS.peek()[pulse]) return ctx.sleep(T / 4);
73 |
74 | // Play kick beat
75 | playInst(sampler, NOTE_KICK);
76 |
77 | ctx.sleep(T / 4);
78 | });
79 |
80 | loop('hats', async ctx => {
81 | hats_pattern = hats[MC_HATS.peekID()];
82 | max = hats_pattern[1];
83 | t = hats_pattern[0];
84 |
85 | // Never muted
86 | playInst(sampler, NOTE_HAT);
87 |
88 | // Visualizer
89 | for (let i = 0; i < 8; i++) {
90 | Visualizer.blink(`/blink/${i}/${h_counter}/2/${sqcr.tickToMS() * t}`);
91 | }
92 |
93 | if (h_counter >= max - 1) {
94 | MC_HATS.next();
95 | h_counter = 0;
96 | } else {
97 | h_counter++;
98 | }
99 |
100 | ctx.sleep(t);
101 | });
102 |
103 | loop('snares', async ctx => {
104 | const pulse = beatFromTick(ctx.tick);
105 | // // Switch pattern on the 0
106 | if (pulse % 8 === 0) MC_SNARES.next();
107 | if (!MC_SNARES.peek()[pulse] || !LEVELS[ctx.name]) return ctx.sleep(T / 4);
108 | playInst(sampler, NOTE_CLAP);
109 | ctx.sleep(T / 4);
110 | });
111 |
112 | loop('vocals', async ctx => {
113 | if (LEVELS.vocals) playInst(sampler, _sample(DRAKE), 8 * 1000);
114 | // Update a bit more frequently
115 | LEVELS.vocals = MC_LEVELS.next();
116 | ctx.sleep(M * 4);
117 | });
118 |
119 | // Init dataviz
120 | window.initViz();
121 |
--------------------------------------------------------------------------------
/public/sqcr-demo/js/notes-graph-synth.js:
--------------------------------------------------------------------------------
1 | var nodes = null;
2 | var edges = null;
3 | var network = null;
4 | var selectedNodeId = 1;
5 |
6 | var note = null;
7 | var duration = 500;
8 |
9 | var NOTES = ['C4', 'D4', 'E4', 'F4', 'G4', 'A4', 'B4'];
10 |
11 | function rand() {
12 | return NOTES[Math.round(Math.random() * (NOTES.length - 1))];
13 | }
14 |
15 | var synth = new Tone.Synth({
16 | oscillator: {
17 | type: 'amtriangle',
18 | harmonicity: 0.5,
19 | modulationType: 'sine',
20 | },
21 | envelope: {
22 | attackCurve: 'exponential',
23 | attack: 0.05,
24 | decay: 0.2,
25 | sustain: 0.2,
26 | release: 1.5,
27 | },
28 | portamento: 0.05,
29 | }).toMaster();
30 |
31 | var G = {
32 | '0': [0, 0, 2, 4],
33 | '1': [1, 1, 3, 5],
34 | '2': [2, 2, 4, 6],
35 | '3': [4],
36 | '4': [4, 0],
37 | '5': [0],
38 | '6': [1, 0],
39 | };
40 |
41 | var MC = new MarkovChain(G, NOTES, 0);
42 |
43 | // create an array with nodes
44 | function makeNodes(obj, labels) {
45 | var nodeStyle = {
46 | font: {
47 | color: '#000000',
48 | face: 'sans-serif',
49 | size: 20,
50 | },
51 | color: {
52 | highlight: {
53 | border: '#ccfa99',
54 | background: '#faf099',
55 | },
56 | },
57 | };
58 | const ids = Object.keys(obj).map(Number);
59 | return ids.map(id => {
60 | return {
61 | id,
62 | value: obj[id].length, // how many edges
63 | label: labels[id],
64 | ...nodeStyle,
65 | };
66 | });
67 | }
68 |
69 | function makeEdges(obj) {
70 | const edgeOptions = {
71 | arrows: {
72 | to: {
73 | enabled: true,
74 | },
75 | },
76 | color: {
77 | highlight: '#99f9fa',
78 | },
79 | };
80 |
81 | const ids = Object.keys(obj).map(Number);
82 | const edges = [];
83 |
84 | // Make matrix
85 | ids.forEach(id => {
86 | let values = {};
87 | obj[id].forEach(edge => {
88 | if (!values[edge]) {
89 | values[edge] = 1;
90 | } else {
91 | values[edge] += 1;
92 | }
93 | });
94 |
95 | Object.keys(values).forEach(k => {
96 | edges.push({
97 | from: id,
98 | to: Number(k),
99 | value: values[k],
100 | ...edgeOptions,
101 | });
102 | });
103 | });
104 |
105 | return edges;
106 | }
107 |
108 | function draw() {
109 | nodes = makeNodes(G, NOTES);
110 |
111 | edges = makeEdges(G);
112 |
113 | // create a network
114 | var container = document.getElementById('graph');
115 | var data = {
116 | nodes: nodes,
117 | edges: edges,
118 | };
119 | var options = {
120 | nodes: {
121 | shape: 'dot',
122 | size: 10,
123 | },
124 | };
125 | network = new vis.Network(container, data, options);
126 | }
127 |
128 | draw();
129 |
130 | network.fit(nodes.map(n => n.id));
131 |
132 | network.selectNodes([MC.peekID()]);
133 |
134 | setInterval(() => {
135 | selectedNodeId = MC.nextID();
136 | network.selectNodes([selectedNodeId]);
137 | note = NOTES[selectedNodeId];
138 | synth.triggerAttackRelease(note, duration);
139 | }, 500);
140 |
--------------------------------------------------------------------------------
/public/sqcr-demo/lib/audiosynth.js:
--------------------------------------------------------------------------------
1 | var Synth, AudioSynth, AudioSynthInstrument;
2 | !function(){
3 |
4 | var URL = window.URL || window.webkitURL;
5 | var Blob = window.Blob;
6 |
7 | if(!URL || !Blob) {
8 | throw new Error('This browser does not support AudioSynth');
9 | }
10 |
11 | var _encapsulated = false;
12 | var AudioSynthInstance = null;
13 | var pack = function(c,arg){ return [new Uint8Array([arg, arg >> 8]), new Uint8Array([arg, arg >> 8, arg >> 16, arg >> 24])][c]; };
14 | var setPrivateVar = function(n,v,w,e){Object.defineProperty(this,n,{value:v,writable:!!w,enumerable:!!e});};
15 | var setPublicVar = function(n,v,w){setPrivateVar.call(this,n,v,w,true);};
16 | AudioSynthInstrument = function AudioSynthInstrument(){this.__init__.apply(this,arguments);};
17 | var setPriv = setPrivateVar.bind(AudioSynthInstrument.prototype);
18 | var setPub = setPublicVar.bind(AudioSynthInstrument.prototype);
19 | setPriv('__init__', function(a,b,c) {
20 | if(!_encapsulated) { throw new Error('AudioSynthInstrument can only be instantiated from the createInstrument method of the AudioSynth object.'); }
21 | setPrivateVar.call(this, '_parent', a);
22 | setPublicVar.call(this, 'name', b);
23 | setPrivateVar.call(this, '_soundID', c);
24 | });
25 | setPub('play', function(note, octave, duration) {
26 | return this._parent.play(this._soundID, note, octave, duration);
27 | });
28 | setPub('generate', function(note, octave, duration) {
29 | return this._parent.generate(this._soundID, note, octave, duration);
30 | });
31 | AudioSynth = function AudioSynth(){if(AudioSynthInstance instanceof AudioSynth){return AudioSynthInstance;}else{ this.__init__(); return this; }};
32 | setPriv = setPrivateVar.bind(AudioSynth.prototype);
33 | setPub = setPublicVar.bind(AudioSynth.prototype);
34 | setPriv('_debug',false,true);
35 | setPriv('_bitsPerSample',16);
36 | setPriv('_channels',1);
37 | setPriv('_sampleRate',44100,true);
38 | setPub('setSampleRate', function(v) {
39 | this._sampleRate = Math.max(Math.min(v|0,44100), 4000);
40 | this._clearCache();
41 | return this._sampleRate;
42 | });
43 | setPub('getSampleRate', function() { return this._sampleRate; });
44 | setPriv('_volume',32768,true);
45 | setPub('setVolume', function(v) {
46 | v = parseFloat(v); if(isNaN(v)) { v = 0; }
47 | v = Math.round(v*32768);
48 | this._volume = Math.max(Math.min(v|0,32768), 0);
49 | this._clearCache();
50 | return this._volume;
51 | });
52 | setPub('getVolume', function() { return Math.round(this._volume/32768*10000)/10000; });
53 | setPriv('_notes',{'C':261.63,'C#':277.18,'D':293.66,'D#':311.13,'E':329.63,'F':346.23,'F#':369.99,'G':392.00,'G#':415.30,'A':440.00,'A#':466.16,'B':493.88});
54 | setPriv('_fileCache',[],true);
55 | setPriv('_temp',{},true);
56 | setPriv('_sounds',[],true);
57 | setPriv('_mod',[function(i,s,f,x){return Math.sin((2 * Math.PI)*(i/s)*f+x);}]);
58 | setPriv('_resizeCache', function() {
59 | var f = this._fileCache;
60 | var l = this._sounds.length;
61 | while(f.length> 8;
121 |
122 | }
123 |
124 | for (; i !== decayLen; i++) {
125 |
126 | val = volume * Math.pow((1-((i-(sampleRate*attack))/(sampleRate*(time-attack)))),dampen) * waveFunc.call(waveBind, i, sampleRate, frequency, volume);
127 |
128 | data[i << 1] = val;
129 | data[(i << 1) + 1] = val >> 8;
130 |
131 | }
132 |
133 | var out = [
134 | 'RIFF',
135 | pack(1, 4 + (8 + 24/* chunk 1 length */) + (8 + 8/* chunk 2 length */)), // Length
136 | 'WAVE',
137 | // chunk 1
138 | 'fmt ', // Sub-chunk identifier
139 | pack(1, 16), // Chunk length
140 | pack(0, 1), // Audio format (1 is linear quantization)
141 | pack(0, channels),
142 | pack(1, sampleRate),
143 | pack(1, sampleRate * channels * bitsPerSample / 8), // Byte rate
144 | pack(0, channels * bitsPerSample / 8),
145 | pack(0, bitsPerSample),
146 | // chunk 2
147 | 'data', // Sub-chunk identifier
148 | pack(1, data.length * channels * bitsPerSample / 8), // Chunk length
149 | data
150 | ];
151 | var blob = new Blob(out, {type: 'audio/wav'});
152 | var dataURI = URL.createObjectURL(blob);
153 | this._fileCache[sound][octave-1][note][time] = dataURI;
154 | if(this._debug) { console.log((new Date).valueOf() - t, 'ms to generate'); }
155 | return dataURI;
156 | }
157 | });
158 | setPub('play', function(sound, note, octave, duration) {
159 | var src = this.generate(sound, note, octave, duration);
160 | var audio = new Audio(src);
161 | audio.play();
162 | return true;
163 | });
164 | setPub('debug', function() { this._debug = true; });
165 | setPub('createInstrument', function(sound) {
166 | var n = 0;
167 | var found = false;
168 | if(typeof(sound)=='string') {
169 | for(var i=0;i=(valueTable.length-1)?0:playVal+1] + valueTable[playVal]) * 0.5;
296 |
297 | if(playVal>=Math.floor(period)) {
298 | if(playVal=p_hundredth) {
300 | // Reset
301 | resetPlay = true;
302 | valueTable[playVal+1] = (valueTable[0] + valueTable[playVal+1]) * 0.5;
303 | vars.periodCount++;
304 | }
305 | } else {
306 | resetPlay = true;
307 | }
308 | }
309 |
310 | var _return = valueTable[playVal];
311 | if(resetPlay) { vars.playVal = 0; } else { vars.playVal++; }
312 |
313 | return _return;
314 |
315 | }
316 | }
317 | },
318 | {
319 | name: 'edm',
320 | attack: function() { return 0.002; },
321 | dampen: function() { return 1; },
322 | wave: function(i, sampleRate, frequency) {
323 | var base = this.modulate[0];
324 | var mod = this.modulate.slice(1);
325 | return mod[0](
326 | i,
327 | sampleRate,
328 | frequency,
329 | mod[9](
330 | i,
331 | sampleRate,
332 | frequency,
333 | mod[2](
334 | i,
335 | sampleRate,
336 | frequency,
337 | Math.pow(base(i, sampleRate, frequency, 0), 3) +
338 | Math.pow(base(i, sampleRate, frequency, 0.5), 5) +
339 | Math.pow(base(i, sampleRate, frequency, 1), 7)
340 | )
341 | ) +
342 | mod[8](
343 | i,
344 | sampleRate,
345 | frequency,
346 | base(i, sampleRate, frequency, 1.75)
347 | )
348 | );
349 | }
350 | });
351 |
--------------------------------------------------------------------------------
/public/sqcr-demo/lib/tonal.js:
--------------------------------------------------------------------------------
1 | !function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(n.Tonal={})}(this,function(n){"use strict";function t(n){"string"!=typeof n&&(n="");var t=T.exec(n);return t?[t[1].toUpperCase(),t[2].replace(/x/g,"##"),t[3],t[4]]:null}function r(n,t){return n=Math.round(n),(!0===t?G:I)[n%12]+(Math.floor(n/12)-1)}function e(n,t){for(var r=[];t--;r[t]=t+n);return r}function m(n,t){for(var r=[];t--;r[t]=n-t);return r}function i(n,t){return null===n||null===t?[]:nan(t)})}function P(n){return o(n).filter(function(n,t,r){return 0===t||n!==r[t-1]})}function M(n){return"string"!=typeof n?An:_n[n]||(_n[n]=xn(n))}function a(n){var t=(n+1)%7;return t<0?7+t:t}function l(n,t){if(1===arguments.length)return function(t){return l(n,t)};var r=Kn(n),e=Qn(t);if(null===r||null===e)return null;var m=1===r.length?[r[0]+e[0]]:[r[0]+e[0],r[1]+e[1]];return mn(Un(m[0],m[1]))}function c(n,t){if(1===arguments.length)return function(t){return c(n,t)};var r=Kn(n);return null===r?null:mn(Un(r[0]+t))}function s(n,t){if(1===arguments.length)return function(t){return s(n,t)};var r=Kn(n),e=Kn(t);return null===e||null===r?null:e[0]-r[0]}function f(n,t){return 1===arguments.length?function(t){return l(t,n)}:l(t,n)}function d(n,t,r){var e=Qn(n),m=Qn(t);if(null===e||null===m)return null;var i=[e[0]+r*m[0],e[1]+r*m[1]];return Dn(Wn(i))}function p(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,1)}function b(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,-1)}function h(n,t){if(1===arguments.length)return function(t){return h(n,t)};var r=Kn(n),e=Kn(t);if(null===r||null===e||r.length!==e.length)return null;var m=1===r.length?[e[0]-r[0],-Math.floor(7*(e[0]-r[0])/12)]:[e[0]-r[0],e[1]-r[1]];return Dn(Wn(m))}function v(n,t){if(1===arguments.length)return function(t){return v(n,t)};var r=L(n),e=L(t);return null!==r.midi&&null!==e.midi?e.midi-r.midi:null!==r.chroma&&null!==e.chroma?(e.chroma-r.chroma+12)%12:null}function A(n){if(y(n))return n;if(!Array.isArray(n))return"";var t=[0,0,0,0,0,0,0,0,0,0,0,0];return n.map(nt).forEach(function(n){t[n]=1}),t.join("")}function g(n){return et=et||i(2048,4095).map(function(n){return n.toString(2)}),"number"==typeof n?et.filter(function(t){return rt(t)===n}):et.slice()}function j(n,t){t=!1!==t;var r=A(n).split("");return Mn(r.map(function(n,e){var m=u(e,r);return t&&"0"===m[0]?null:m.join("")}))}function y(n){return mt.test(n)}function O(n){return y(n)?Mn(n.split("").map(function(n,t){return"1"===n?it[t]:null})):[]}function x(n,t){return 1===arguments.length?function(t){return x(n,t)}:A(n)===A(t)}function _(n,t){return arguments.length>1?_(n)(t):(n=tt(n),function(t){return(t=tt(t))!==n&&(t&n)===t})}function z(n,t){return arguments.length>1?z(n)(t):(n=tt(n),function(t){return(t=tt(t))!==n&&(t|n)===t})}function q(n,t){return arguments.length>1?q(n)(t):(n=A(n),function(t){return"1"===n[nt(t)]})}function k(n,t){return 1===arguments.length?function(t){return k(n,t)}:t.filter(q(n))}function S(n,t){var r=D(n);return t=t||r[1],pt(t).map(l(r[0]))}function w(n){var t=D(n);return void 0!==Mt(t[1])}function D(n){if("string"!=typeof n)return["",""];var t=n.indexOf(" "),r=R(n.substring(0,t))||R(n)||"",e=""!==r?n.substring(r.length+1):n;return[r,e.length?e:""]}function E(n,t){var r=C(n);return t=t||r[1],xt(t).intervals.map(l(r[0]))}function C(n){var r=t(n);return""===r[0]?["",n]:"A"===r[0]&&"ug"===r[3]?["","aug"]:St.test(r[2])?[r[0]+r[1],r[2]+r[3]]:[r[0]+r[1]+r[2],r[3]]}var $="C C# Db D D# Eb E F F# Gb G G# Ab A A# Bb B".split(" "),F=function(n){return"string"!=typeof n?$.slice():$.filter(function(t){var r=t[1]||" ";return-1!==n.indexOf(r)})},G=F(" #"),I=F(" b"),T=/^([a-gA-G]?)(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)$/,B=Object.freeze({pc:null,name:null,step:null,alt:null,oct:null,octStr:null,chroma:null,midi:null,freq:null}),N=[0,2,4,5,7,9,11],L=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var r=t(n);if(""===r[0]||""!==r[3])return B;var e=r[0],m=r[1],i=r[2],u={letter:e,acc:m,octStr:i};return u.pc=u.letter+u.acc,u.name=u.pc+i,u.step=(u.letter.charCodeAt(0)+3)%7,u.alt="b"===u.acc[0]?-u.acc.length:u.acc.length,u.oct=i.length?+i:null,u.chroma=(N[u.step]+u.alt+120)%12,u.midi=null!==u.oct?N[u.step]+u.alt+12*(u.oct+1):null,u.freq=J(u.midi),Object.freeze(u)}),R=function(n){return L(n).name},U=function(n){return L(n).pc},H=function(n){return L(n).midi||+n||null},J=function(n,t){return void 0===t&&(t=440),"number"==typeof n?Math.pow(2,(n-69)/12)*t:null},K=function(n){return L(n).freq||J(n)},Q=Math.log(2),V=Math.log(440),W=function(n){var t=12*(Math.log(n)-V)/Q+69;return Math.round(100*t)/100},X=function(n){return L(n).chroma},Y=function(n){return L(n).oct},Z=function(n){return"CDEFGAB"[n]},nn=function(n,t){return Array(t+1).join(n)},tn=function(n,t){return"number"!=typeof n?"":t(n)},rn=function(n){return tn(n,function(n){return n<0?nn("b",-n):nn("#",n)})},en=function(n,t){void 0===n&&(n={}),void 0===t&&(t=null);var r=t?Object.assign({},L(t),n):n,e=r.step,m=r.alt,i=r.oct,u=Z(e);if(!u)return null;var o=u+rn(m);return i||0===i?o+i:o},mn=en,un=function(n,t){var e=L(n),m=e.alt,i=e.chroma,u=e.midi;if(null===i)return null;var o=!1===t?m<0:m>0;return null===u?U(r(i,o)):r(u,o)},on=function(n){return un(n,!1)},Pn=Object.freeze({names:F,tokenize:t,props:L,name:R,pc:U,midi:H,midiToFreq:J,freq:K,freqToMidi:W,chroma:X,oct:Y,stepToLetter:Z,altToAcc:rn,from:en,build:mn,fromMidi:r,simplify:un,enharmonic:on}),Mn=function(n){return n.filter(function(n){return 0===n||n})},an=function(n){var t=H(n);return null!==t?t:H(n+"-100")},ln=function(n,t){void 0===t&&(t=Math.random);for(var r,e,m=n.length;m;)r=t()*m--|0,e=n[m],n[m]=n[r],n[r]=e;return n},cn=function(n){return 0===n.length?[[]]:cn(n.slice(1)).reduce(function(t,r){return t.concat(n.map(function(t,e){var m=r.slice();return m.splice(e,0,n[0]),m}))},[])},sn=Object.freeze({range:i,rotate:u,compact:Mn,sort:o,unique:P,shuffle:ln,permutations:cn}),fn=new RegExp("^([-+]?\\d+)(d{1,4}|m|M|P|A{1,4})|(AA|A|P|M|m|d|dd)([-+]?\\d+)$"),dn=[0,2,4,5,7,9,11],pn=[0,1,2,3,4,5,6,5,4,3,2,1],bn="1P 2m 2M 3m 3M 4P 5P 6m 6M 7m 7M 8P".split(" "),hn=function(n){return"string"!=typeof n?bn.slice():bn.filter(function(t){return-1!==n.indexOf(t[1])})},vn=function(n){var t=fn.exec(n);return null===t?null:t[1]?[t[1],t[2]]:[t[4],t[3]]},An=Object.freeze({name:null,num:null,q:null,step:null,alt:null,dir:null,type:null,simple:null,semitones:null,chroma:null}),gn=function(n,t){return Array(Math.abs(t)+1).join(n)},jn=function(n,t){return"M"===t&&"M"===n?0:"P"===t&&"P"===n?0:"m"===t&&"M"===n?-1:/^A+$/.test(t)?t.length:/^d+$/.test(t)?"P"===n?-t.length:-t.length-1:null},yn=function(n,t){return 0===t?"M"===n?"M":"P":-1===t&&"M"===n?"m":t>0?gn("A",t):t<0?gn("d","P"===n?t:t+1):null},On=function(n){return(Math.abs(n)-1)%7},xn=function(n){var t=vn(n);if(null===t)return An;var r={num:+t[0],q:t[1]};return r.step=On(r.num),r.type="PMMPPMM"[r.step],"M"===r.type&&"P"===r.q?An:(r.name=""+r.num+r.q,r.dir=r.num<0?-1:1,r.simple=8===r.num||-8===r.num?r.num:r.dir*(r.step+1),r.alt=jn(r.type,r.q),r.oct=Math.floor((Math.abs(r.num)-1)/7),r.semitones=r.dir*(dn[r.step]+r.alt+12*r.oct),r.chroma=(r.dir*(dn[r.step]+r.alt)%12+12)%12,Object.freeze(r))},_n={},zn=function(n){return M(n).num},qn=function(n){return M(n).name},kn=function(n){return M(n).semitones},Sn=function(n){return M(n).chroma},wn=function(n){return"string"==typeof n&&(n=M(n).chroma),"number"==typeof n?pn[n%12]:null},Dn=function(n){void 0===n&&(n={});var t=n.num,r=n.step,e=n.alt,m=n.oct;void 0===m&&(m=1);var i=n.dir;if(void 0!==r&&(t=r+1+7*m),void 0===t)return null;var u=i<0?"-":"",o="PMMPPMM"[On(t)];return u+t+yn(o,e)},En=function(n){var t=M(n);return t===An?null:t.simple+t.q},Cn=function(n){var t=M(n);if(t===An)return null;var r=(7-t.step)%7,e="P"===t.type?-t.alt:-(t.alt+1);return Dn({step:r,alt:e,oct:t.oct,dir:t.dir})},$n=[1,2,2,3,3,4,5,5,6,6,7,7],Fn="P m M m M P d P m M m M".split(" "),Gn=function(n){var t=n<0?-1:1,r=Math.abs(n),e=r%12,m=Math.floor(r/12);return t*($n[e]+7*m)+Fn[e]},In=Object.freeze({names:hn,tokenize:vn,props:M,num:zn,name:qn,semitones:kn,chroma:Sn,ic:wn,build:Dn,simplify:En,invert:Cn,fromSemitones:Gn}),Tn=[0,2,4,-1,1,3,5],Bn=function(n){return Math.floor(7*n/12)},Nn=Tn.map(Bn),Ln=function(n){var t=n.step,r=n.alt,e=n.oct,m=n.dir;void 0===m&&(m=1);var i=Tn[t]+7*r;return null===e?[m*i]:[m*i,m*(e-Nn[t]-4*r)]},Rn=[3,0,4,1,5,2,6],Un=function(n,t,r){var e=Rn[a(n)],m=Math.floor((n+1)/7);return void 0===t?{step:e,alt:m,dir:r}:{step:e,alt:m,oct:t+4*m+Nn[e],dir:r}},Hn=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}},Jn=function(n){return Hn(function(t){var r=n(t);return null===r.name?null:Ln(r)})},Kn=Jn(L),Qn=Jn(M),Vn=function(n){return 7*n[0]+12*n[1]<0},Wn=function(n){return Vn(n)?Un(-n[0],-n[1],-1):Un(n[0],n[1],1)},Xn=Object.freeze({transpose:l,trFifths:c,fifths:s,transposeBy:f,addIntervals:d,add:p,subtract:b,interval:h,semitones:v}),Yn={chromatic:["1P 2m 2M 3m 3M 4P 4A 5P 6m 6M 7m 7M"],lydian:["1P 2M 3M 4A 5P 6M 7M"],major:["1P 2M 3M 4P 5P 6M 7M",["ionian"]],mixolydian:["1P 2M 3M 4P 5P 6M 7m",["dominant"]],dorian:["1P 2M 3m 4P 5P 6M 7m"],aeolian:["1P 2M 3m 4P 5P 6m 7m",["minor"]],phrygian:["1P 2m 3m 4P 5P 6m 7m"],locrian:["1P 2m 3m 4P 5d 6m 7m"],altered:["1P 2m 3m 3M 5d 6m 7m",["super locrian","diminished whole tone","pomeroy"]],iwato:["1P 2m 4P 5d 7m"],hirajoshi:["1P 2M 3m 5P 6m"],kumoijoshi:["1P 2m 4P 5P 6m"],pelog:["1P 2m 3m 5P 6m"],prometheus:["1P 2M 3M 4A 6M 7m"],ritusen:["1P 2M 4P 5P 6M"],scriabin:["1P 2m 3M 5P 6M"],piongio:["1P 2M 4P 5P 6M 7m"],augmented:["1P 2A 3M 5P 5A 7M"],neopolitan:["1P 2m 3m 4P 5P 6m 7M"],diminished:["1P 2M 3m 4P 5d 6m 6M 7M"],egyptian:["1P 2M 4P 5P 7m"],oriental:["1P 2m 3M 4P 5d 6M 7m"],spanish:["1P 2m 3M 4P 5P 6m 7m",["phrygian major"]],flamenco:["1P 2m 3m 3M 4A 5P 7m"],balinese:["1P 2m 3m 4P 5P 6m 7M"],persian:["1P 2m 3M 4P 5d 6m 7M"],bebop:["1P 2M 3M 4P 5P 6M 7m 7M"],enigmatic:["1P 2m 3M 5d 6m 7m 7M"],ichikosucho:["1P 2M 3M 4P 5d 5P 6M 7M"],"melodic minor":["1P 2M 3m 4P 5P 6M 7M"],"melodic minor second mode":["1P 2m 3m 4P 5P 6M 7m"],"lydian augmented":["1P 2M 3M 4A 5A 6M 7M"],"lydian dominant":["1P 2M 3M 4A 5P 6M 7m",["lydian b7"]],"melodic minor fifth mode":["1P 2M 3M 4P 5P 6m 7m",["hindu","mixolydian b6M"]],"locrian #2":["1P 2M 3m 4P 5d 6m 7m"],"locrian major":["1P 2M 3M 4P 5d 6m 7m",["arabian"]],"major pentatonic":["1P 2M 3M 5P 6M",["pentatonic"]],"lydian pentatonic":["1P 3M 4A 5P 7M",["chinese"]],"mixolydian pentatonic":["1P 3M 4P 5P 7m",["indian"]],"locrian pentatonic":["1P 3m 4P 5d 7m",["minor seven flat five pentatonic"]],"minor pentatonic":["1P 3m 4P 5P 7m"],"minor six pentatonic":["1P 3m 4P 5P 6M"],"minor hexatonic":["1P 2M 3m 4P 5P 7M"],"flat three pentatonic":["1P 2M 3m 5P 6M",["kumoi"]],"flat six pentatonic":["1P 2M 3M 5P 6m"],"major flat two pentatonic":["1P 2m 3M 5P 6M"],"whole tone pentatonic":["1P 3M 5d 6m 7m"],"ionian pentatonic":["1P 3M 4P 5P 7M"],"lydian #5P pentatonic":["1P 3M 4A 5A 7M"],"lydian dominant pentatonic":["1P 3M 4A 5P 7m"],"minor #7M pentatonic":["1P 3m 4P 5P 7M"],"super locrian pentatonic":["1P 3m 4d 5d 7m"],"in-sen":["1P 2m 4P 5P 7m"],"vietnamese 1":["1P 3m 4P 5P 6m"],"vietnamese 2":["1P 3m 4P 5P 7m"],"prometheus neopolitan":["1P 2m 3M 4A 6M 7m"],"major blues":["1P 2M 3m 3M 5P 6M"],"minor blues":["1P 3m 4P 5d 5P 7m",["blues"]],"composite blues":["1P 2M 3m 3M 4P 5d 5P 6M 7m"],"augmented heptatonic":["1P 2A 3M 4P 5P 5A 7M"],"dorian #4":["1P 2M 3m 4A 5P 6M 7m"],"lydian diminished":["1P 2M 3m 4A 5P 6M 7M"],"whole tone":["1P 2M 3M 4A 5A 7m"],"leading whole tone":["1P 2M 3M 4A 5A 7m 7M"],"harmonic minor":["1P 2M 3m 4P 5P 6m 7M"],"lydian minor":["1P 2M 3M 4A 5P 6m 7m"],"neopolitan minor":["1P 2m 3m 4P 5P 6m 7M"],"neopolitan major":["1P 2m 3m 4P 5P 6M 7M",["dorian b2"]],"neopolitan major pentatonic":["1P 3M 4P 5d 7m"],"romanian minor":["1P 2M 3m 5d 5P 6M 7m"],"double harmonic lydian":["1P 2m 3M 4A 5P 6m 7M"],"harmonic major":["1P 2M 3M 4P 5P 6m 7M"],"double harmonic major":["1P 2m 3M 4P 5P 6m 7M",["gypsy"]],"hungarian minor":["1P 2M 3m 4A 5P 6m 7M"],"hungarian major":["1P 2A 3M 4A 5P 6M 7m"],"spanish heptatonic":["1P 2m 3m 3M 4P 5P 6m 7m"],"todi raga":["1P 2m 3m 4A 5P 6m 7M"],"malkos raga":["1P 3m 4P 6m 7m"],"kafi raga":["1P 3m 3M 4P 5P 6M 7m 7M"],"purvi raga":["1P 2m 3M 4P 4A 5P 6m 7M"],"bebop dominant":["1P 2M 3M 4P 5P 6M 7m 7M"],"bebop minor":["1P 2M 3m 3M 4P 5P 6M 7m"],"bebop major":["1P 2M 3M 4P 5P 5A 6M 7M"],"bebop locrian":["1P 2m 3m 4P 5d 5P 6m 7m"],"minor bebop":["1P 2M 3m 4P 5P 6m 7m 7M"],"mystery #1":["1P 2m 3M 5d 6m 7m"],"minor six diminished":["1P 2M 3m 4P 5P 6m 6M 7M"],"ionian augmented":["1P 2M 3M 4P 5A 6M 7M"],"lydian #9":["1P 2m 3M 4A 5P 6M 7M"],"six tone symmetric":["1P 2m 3M 4P 5A 6M"]},Zn={M:["1P 3M 5P",["Major",""]],M13:["1P 3M 5P 7M 9M 13M",["maj13","Maj13"]],M6:["1P 3M 5P 13M",["6"]],M69:["1P 3M 5P 6M 9M",["69"]],M7add13:["1P 3M 5P 6M 7M 9M"],M7b5:["1P 3M 5d 7M"],M7b6:["1P 3M 6m 7M"],M7b9:["1P 3M 5P 7M 9m"],M7sus4:["1P 4P 5P 7M"],M9:["1P 3M 5P 7M 9M",["maj9","Maj9"]],M9b5:["1P 3M 5d 7M 9M"],M9sus4:["1P 4P 5P 7M 9M"],Madd9:["1P 3M 5P 9M",["2","add9","add2"]],Maj7:["1P 3M 5P 7M",["maj7","M7"]],Mb5:["1P 3M 5d"],Mb6:["1P 3M 13m"],Msus2:["1P 2M 5P",["add9no3","sus2"]],Msus4:["1P 4P 5P",["sus","sus4"]],Maddb9:["1P 3M 5P 9m"],m:["1P 3m 5P"],m11:["1P 3m 5P 7m 9M 11P",["_11"]],m11b5:["1P 3m 7m 12d 2M 4P",["h11","_11b5"]],m13:["1P 3m 5P 7m 9M 11P 13M",["_13"]],m6:["1P 3m 4P 5P 13M",["_6"]],m69:["1P 3m 5P 6M 9M",["_69"]],m7:["1P 3m 5P 7m",["minor7","_","_7"]],m7add11:["1P 3m 5P 7m 11P",["m7add4"]],m7b5:["1P 3m 5d 7m",["half-diminished","h7","_7b5"]],m9:["1P 3m 5P 7m 9M",["_9"]],m9b5:["1P 3m 7m 12d 2M",["h9","-9b5"]],mMaj7:["1P 3m 5P 7M",["mM7","_M7"]],mMaj7b6:["1P 3m 5P 6m 7M",["mM7b6"]],mM9:["1P 3m 5P 7M 9M",["mMaj9","-M9"]],mM9b6:["1P 3m 5P 6m 7M 9M",["mMaj9b6"]],mb6M7:["1P 3m 6m 7M"],mb6b9:["1P 3m 6m 9m"],o:["1P 3m 5d",["mb5","dim"]],o7:["1P 3m 5d 13M",["diminished","m6b5","dim7"]],o7M7:["1P 3m 5d 6M 7M"],oM7:["1P 3m 5d 7M"],sus24:["1P 2M 4P 5P",["sus4add9"]],madd4:["1P 3m 4P 5P"],madd9:["1P 3m 5P 9M"],4:["1P 4P 7m 10m",["quartal"]],5:["1P 5P"],7:["1P 3M 5P 7m",["Dominant","Dom"]],9:["1P 3M 5P 7m 9M",["79"]],11:["1P 5P 7m 9M 11P"],13:["1P 3M 5P 7m 9M 13M",["13_"]],64:["5P 8P 10M"],"M#5":["1P 3M 5A",["augmented","maj#5","Maj#5","+","aug"]],"M#5add9":["1P 3M 5A 9M",["+add9"]],"M13#11":["1P 3M 5P 7M 9M 11A 13M",["maj13#11","Maj13#11","M13+4","M13#4"]],"M6#11":["1P 3M 5P 6M 11A",["M6b5","6#11","6b5"]],"M69#11":["1P 3M 5P 6M 9M 11A"],"M7#11":["1P 3M 5P 7M 11A",["maj7#11","Maj7#11","M7+4","M7#4"]],"M7#5":["1P 3M 5A 7M",["maj7#5","Maj7#5","maj9#5","M7+"]],"M7#5sus4":["1P 4P 5A 7M"],"M7#9#11":["1P 3M 5P 7M 9A 11A"],"M9#11":["1P 3M 5P 7M 9M 11A",["maj9#11","Maj9#11","M9+4","M9#4"]],"M9#5":["1P 3M 5A 7M 9M",["Maj9#5"]],"M9#5sus4":["1P 4P 5A 7M 9M"],"11b9":["1P 5P 7m 9m 11P"],"13#11":["1P 3M 5P 7m 9M 11A 13M",["13+4","13#4"]],"13#9":["1P 3M 5P 7m 9A 13M",["13#9_"]],"13#9#11":["1P 3M 5P 7m 9A 11A 13M"],"13b5":["1P 3M 5d 6M 7m 9M"],"13b9":["1P 3M 5P 7m 9m 13M"],"13b9#11":["1P 3M 5P 7m 9m 11A 13M"],"13no5":["1P 3M 7m 9M 13M"],"13sus4":["1P 4P 5P 7m 9M 13M",["13sus"]],"69#11":["1P 3M 5P 6M 9M 11A"],"7#11":["1P 3M 5P 7m 11A",["7+4","7#4","7#11_","7#4_"]],"7#11b13":["1P 3M 5P 7m 11A 13m",["7b5b13"]],"7#5":["1P 3M 5A 7m",["+7","7aug","aug7"]],"7#5#9":["1P 3M 5A 7m 9A",["7alt","7#5#9_","7#9b13_"]],"7#5b9":["1P 3M 5A 7m 9m"],"7#5b9#11":["1P 3M 5A 7m 9m 11A"],"7#5sus4":["1P 4P 5A 7m"],"7#9":["1P 3M 5P 7m 9A",["7#9_"]],"7#9#11":["1P 3M 5P 7m 9A 11A",["7b5#9"]],"7#9#11b13":["1P 3M 5P 7m 9A 11A 13m"],"7#9b13":["1P 3M 5P 7m 9A 13m"],"7add6":["1P 3M 5P 7m 13M",["67","7add13"]],"7b13":["1P 3M 7m 13m"],"7b5":["1P 3M 5d 7m"],"7b6":["1P 3M 5P 6m 7m"],"7b9":["1P 3M 5P 7m 9m"],"7b9#11":["1P 3M 5P 7m 9m 11A",["7b5b9"]],"7b9#9":["1P 3M 5P 7m 9m 9A"],"7b9b13":["1P 3M 5P 7m 9m 13m"],"7b9b13#11":["1P 3M 5P 7m 9m 11A 13m",["7b9#11b13","7b5b9b13"]],"7no5":["1P 3M 7m"],"7sus4":["1P 4P 5P 7m",["7sus"]],"7sus4b9":["1P 4P 5P 7m 9m",["susb9","7susb9","7b9sus","7b9sus4","phryg"]],"7sus4b9b13":["1P 4P 5P 7m 9m 13m",["7b9b13sus4"]],"9#11":["1P 3M 5P 7m 9M 11A",["9+4","9#4","9#11_","9#4_"]],"9#11b13":["1P 3M 5P 7m 9M 11A 13m",["9b5b13"]],"9#5":["1P 3M 5A 7m 9M",["9+"]],"9#5#11":["1P 3M 5A 7m 9M 11A"],"9b13":["1P 3M 7m 9M 13m"],"9b5":["1P 3M 5d 7m 9M"],"9no5":["1P 3M 7m 9M"],"9sus4":["1P 4P 5P 7m 9M",["9sus"]],"m#5":["1P 3m 5A",["m+","mb6"]],"m11A 5":["1P 3m 6m 7m 9M 11P"],"m7#5":["1P 3m 6m 7m"],"m9#5":["1P 3m 6m 7m 9M"],"+add#9":["1P 3M 5A 9A"]},nt=function(n){return X(n)||Sn(n)||0},tt=function(n){return parseInt(A(n),2)},rt=function(n){return n.replace(/0/g,"").length},et=null,mt=/^[01]{12}$/,it="1P 2m 2M 3m 3M 4P 5d 5P 6m 6M 7m 7M".split(" "),ut=Object.freeze({chroma:A,chromas:g,modes:j,isChroma:y,intervals:O,isEqual:x,isSubsetOf:_,isSupersetOf:z,includes:q,filter:k}),ot=function(n){var t=Object.keys(n).sort(),r=[],e=[],m=function(n,t,m){r[n]=t,e[m]=e[m]||[],e[m].push(n)};t.forEach(function(t){var r=n[t][0].split(" "),e=n[t][1],i=A(r);m(t,r,i),e&&e.forEach(function(n){return m(n,r,i)})});var i=Object.keys(r).sort(),u=function(n){return r[n]};return u.names=function(n){return"string"==typeof n?(e[n]||[]).slice():(!0===n?i:t).slice()},u},Pt=function(n,t){var r=function(r){return n(r)||t(r)};return r.names=function(r){return n.names(r).concat(t.names(r))},r},Mt=ot(Yn),at=ot(Zn),lt=Pt(Mt,at),ct=Object.freeze({dictionary:ot,combine:Pt,scale:Mt,chord:at,pcset:lt}),st=Object.freeze({name:null,intervals:[],names:[],chroma:null,setnum:null}),ft=function(n,t){return function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=Mt(n);if(!t)return st;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=Mt.names(r.chroma),Object.freeze(r)},{}),dt=Mt.names,pt=function(n){var t=D(n);return ft(t[1]).intervals},bt=function(n){var t=pt(n),r=S(n);return j(t).map(function(n,e){var m=Mt.names(n)[0];if(m)return[r[e]||t[e],m]}).filter(function(n){return n})},ht=function(n){var t=_(pt(n));return at.names().filter(function(n){return t(at(n))})},vt=function(n){var t=Mn(n.map(U));if(!t.length)return t;var r=t[0],e=P(t);return u(e.indexOf(r),e)},At=function(n){if(!pt(n).length)return[];var t=z(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},gt=function(n){var t=_(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},jt=Object.freeze({props:ft,names:dt,intervals:pt,notes:S,exists:w,tokenize:D,modeNames:bt,chords:ht,toScale:vt,supersets:At,subsets:gt}),yt=at.names,Ot=Object.freeze({name:null,names:[],intervals:[],chroma:null,setnum:null}),xt=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=at(n);if(!t)return Ot;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=at.names(r.chroma),r}),_t=function(n){return xt(C(n)[1]).intervals},zt=function(n){return void 0!==at(C(n)[1])},qt=function(n){if(!_t(n).length)return[];var t=z(_t(n));return at.names().filter(function(n){return t(at(n))})},kt=function(n){var t=_(_t(n));return at.names().filter(function(n){return t(at(n))})},St=/^(6|64|7|9|11|13)$/,wt=Object.freeze({names:yt,props:xt,intervals:_t,notes:E,exists:zt,supersets:qt,subsets:kt,tokenize:C}),Dt=l,Et=h,Ct=L,$t=H,Ft=K,Gt=at,It=Mt;n.Array=sn,n.Note=Pn,n.Interval=In,n.Distance=Xn,n.Scale=jt,n.Chord=wt,n.PcSet=ut,n.Dictionary=ct,n.transpose=Dt,n.interval=Et,n.note=Ct,n.midi=$t,n.freq=Ft,n.chord=Gt,n.scale=It,Object.defineProperty(n,"__esModule",{value:!0})});
2 | //# sourceMappingURL=tonal.min.js.map
3 |
--------------------------------------------------------------------------------
/public/sqcr-demo/lib/transpiled.js:
--------------------------------------------------------------------------------
1 | !function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(n.Tonal={})}(this,function(n){"use strict";function t(n){"string"!=typeof n&&(n="");var t=T.exec(n);return t?[t[1].toUpperCase(),t[2].replace(/x/g,"##"),t[3],t[4]]:null}function r(n,t){return n=Math.round(n),(!0===t?G:I)[n%12]+(Math.floor(n/12)-1)}function e(n,t){for(var r=[];t--;r[t]=t+n);return r}function m(n,t){for(var r=[];t--;r[t]=n-t);return r}function i(n,t){return null===n||null===t?[]:nan(t)})}function P(n){return o(n).filter(function(n,t,r){return 0===t||n!==r[t-1]})}function M(n){return"string"!=typeof n?An:_n[n]||(_n[n]=xn(n))}function a(n){var t=(n+1)%7;return t<0?7+t:t}function l(n,t){if(1===arguments.length)return function(t){return l(n,t)};var r=Kn(n),e=Qn(t);if(null===r||null===e)return null;var m=1===r.length?[r[0]+e[0]]:[r[0]+e[0],r[1]+e[1]];return mn(Un(m[0],m[1]))}function c(n,t){if(1===arguments.length)return function(t){return c(n,t)};var r=Kn(n);return null===r?null:mn(Un(r[0]+t))}function s(n,t){if(1===arguments.length)return function(t){return s(n,t)};var r=Kn(n),e=Kn(t);return null===e||null===r?null:e[0]-r[0]}function f(n,t){return 1===arguments.length?function(t){return l(t,n)}:l(t,n)}function d(n,t,r){var e=Qn(n),m=Qn(t);if(null===e||null===m)return null;var i=[e[0]+r*m[0],e[1]+r*m[1]];return Dn(Wn(i))}function p(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,1)}function b(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,-1)}function h(n,t){if(1===arguments.length)return function(t){return h(n,t)};var r=Kn(n),e=Kn(t);if(null===r||null===e||r.length!==e.length)return null;var m=1===r.length?[e[0]-r[0],-Math.floor(7*(e[0]-r[0])/12)]:[e[0]-r[0],e[1]-r[1]];return Dn(Wn(m))}function v(n,t){if(1===arguments.length)return function(t){return v(n,t)};var r=L(n),e=L(t);return null!==r.midi&&null!==e.midi?e.midi-r.midi:null!==r.chroma&&null!==e.chroma?(e.chroma-r.chroma+12)%12:null}function A(n){if(y(n))return n;if(!Array.isArray(n))return"";var t=[0,0,0,0,0,0,0,0,0,0,0,0];return n.map(nt).forEach(function(n){t[n]=1}),t.join("")}function g(n){return et=et||i(2048,4095).map(function(n){return n.toString(2)}),"number"==typeof n?et.filter(function(t){return rt(t)===n}):et.slice()}function j(n,t){t=!1!==t;var r=A(n).split("");return Mn(r.map(function(n,e){var m=u(e,r);return t&&"0"===m[0]?null:m.join("")}))}function y(n){return mt.test(n)}function O(n){return y(n)?Mn(n.split("").map(function(n,t){return"1"===n?it[t]:null})):[]}function x(n,t){return 1===arguments.length?function(t){return x(n,t)}:A(n)===A(t)}function _(n,t){return arguments.length>1?_(n)(t):(n=tt(n),function(t){return(t=tt(t))!==n&&(t&n)===t})}function z(n,t){return arguments.length>1?z(n)(t):(n=tt(n),function(t){return(t=tt(t))!==n&&(t|n)===t})}function q(n,t){return arguments.length>1?q(n)(t):(n=A(n),function(t){return"1"===n[nt(t)]})}function k(n,t){return 1===arguments.length?function(t){return k(n,t)}:t.filter(q(n))}function S(n,t){var r=D(n);return t=t||r[1],pt(t).map(l(r[0]))}function w(n){var t=D(n);return void 0!==Mt(t[1])}function D(n){if("string"!=typeof n)return["",""];var t=n.indexOf(" "),r=R(n.substring(0,t))||R(n)||"",e=""!==r?n.substring(r.length+1):n;return[r,e.length?e:""]}function E(n,t){var r=C(n);return t=t||r[1],xt(t).intervals.map(l(r[0]))}function C(n){var r=t(n);return""===r[0]?["",n]:"A"===r[0]&&"ug"===r[3]?["","aug"]:St.test(r[2])?[r[0]+r[1],r[2]+r[3]]:[r[0]+r[1]+r[2],r[3]]}var $="C C# Db D D# Eb E F F# Gb G G# Ab A A# Bb B".split(" "),F=function(n){return"string"!=typeof n?$.slice():$.filter(function(t){var r=t[1]||" ";return-1!==n.indexOf(r)})},G=F(" #"),I=F(" b"),T=/^([a-gA-G]?)(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)$/,B=Object.freeze({pc:null,name:null,step:null,alt:null,oct:null,octStr:null,chroma:null,midi:null,freq:null}),N=[0,2,4,5,7,9,11],L=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var r=t(n);if(""===r[0]||""!==r[3])return B;var e=r[0],m=r[1],i=r[2],u={letter:e,acc:m,octStr:i};return u.pc=u.letter+u.acc,u.name=u.pc+i,u.step=(u.letter.charCodeAt(0)+3)%7,u.alt="b"===u.acc[0]?-u.acc.length:u.acc.length,u.oct=i.length?+i:null,u.chroma=(N[u.step]+u.alt+120)%12,u.midi=null!==u.oct?N[u.step]+u.alt+12*(u.oct+1):null,u.freq=J(u.midi),Object.freeze(u)}),R=function(n){return L(n).name},U=function(n){return L(n).pc},H=function(n){return L(n).midi||+n||null},J=function(n,t){return void 0===t&&(t=440),"number"==typeof n?Math.pow(2,(n-69)/12)*t:null},K=function(n){return L(n).freq||J(n)},Q=Math.log(2),V=Math.log(440),W=function(n){var t=12*(Math.log(n)-V)/Q+69;return Math.round(100*t)/100},X=function(n){return L(n).chroma},Y=function(n){return L(n).oct},Z=function(n){return"CDEFGAB"[n]},nn=function(n,t){return Array(t+1).join(n)},tn=function(n,t){return"number"!=typeof n?"":t(n)},rn=function(n){return tn(n,function(n){return n<0?nn("b",-n):nn("#",n)})},en=function(n,t){void 0===n&&(n={}),void 0===t&&(t=null);var r=t?Object.assign({},L(t),n):n,e=r.step,m=r.alt,i=r.oct,u=Z(e);if(!u)return null;var o=u+rn(m);return i||0===i?o+i:o},mn=en,un=function(n,t){var e=L(n),m=e.alt,i=e.chroma,u=e.midi;if(null===i)return null;var o=!1===t?m<0:m>0;return null===u?U(r(i,o)):r(u,o)},on=function(n){return un(n,!1)},Pn=Object.freeze({names:F,tokenize:t,props:L,name:R,pc:U,midi:H,midiToFreq:J,freq:K,freqToMidi:W,chroma:X,oct:Y,stepToLetter:Z,altToAcc:rn,from:en,build:mn,fromMidi:r,simplify:un,enharmonic:on}),Mn=function(n){return n.filter(function(n){return 0===n||n})},an=function(n){var t=H(n);return null!==t?t:H(n+"-100")},ln=function(n,t){void 0===t&&(t=Math.random);for(var r,e,m=n.length;m;)r=t()*m--|0,e=n[m],n[m]=n[r],n[r]=e;return n},cn=function(n){return 0===n.length?[[]]:cn(n.slice(1)).reduce(function(t,r){return t.concat(n.map(function(t,e){var m=r.slice();return m.splice(e,0,n[0]),m}))},[])},sn=Object.freeze({range:i,rotate:u,compact:Mn,sort:o,unique:P,shuffle:ln,permutations:cn}),fn=new RegExp("^([-+]?\\d+)(d{1,4}|m|M|P|A{1,4})|(AA|A|P|M|m|d|dd)([-+]?\\d+)$"),dn=[0,2,4,5,7,9,11],pn=[0,1,2,3,4,5,6,5,4,3,2,1],bn="1P 2m 2M 3m 3M 4P 5P 6m 6M 7m 7M 8P".split(" "),hn=function(n){return"string"!=typeof n?bn.slice():bn.filter(function(t){return-1!==n.indexOf(t[1])})},vn=function(n){var t=fn.exec(n);return null===t?null:t[1]?[t[1],t[2]]:[t[4],t[3]]},An=Object.freeze({name:null,num:null,q:null,step:null,alt:null,dir:null,type:null,simple:null,semitones:null,chroma:null}),gn=function(n,t){return Array(Math.abs(t)+1).join(n)},jn=function(n,t){return"M"===t&&"M"===n?0:"P"===t&&"P"===n?0:"m"===t&&"M"===n?-1:/^A+$/.test(t)?t.length:/^d+$/.test(t)?"P"===n?-t.length:-t.length-1:null},yn=function(n,t){return 0===t?"M"===n?"M":"P":-1===t&&"M"===n?"m":t>0?gn("A",t):t<0?gn("d","P"===n?t:t+1):null},On=function(n){return(Math.abs(n)-1)%7},xn=function(n){var t=vn(n);if(null===t)return An;var r={num:+t[0],q:t[1]};return r.step=On(r.num),r.type="PMMPPMM"[r.step],"M"===r.type&&"P"===r.q?An:(r.name=""+r.num+r.q,r.dir=r.num<0?-1:1,r.simple=8===r.num||-8===r.num?r.num:r.dir*(r.step+1),r.alt=jn(r.type,r.q),r.oct=Math.floor((Math.abs(r.num)-1)/7),r.semitones=r.dir*(dn[r.step]+r.alt+12*r.oct),r.chroma=(r.dir*(dn[r.step]+r.alt)%12+12)%12,Object.freeze(r))},_n={},zn=function(n){return M(n).num},qn=function(n){return M(n).name},kn=function(n){return M(n).semitones},Sn=function(n){return M(n).chroma},wn=function(n){return"string"==typeof n&&(n=M(n).chroma),"number"==typeof n?pn[n%12]:null},Dn=function(n){void 0===n&&(n={});var t=n.num,r=n.step,e=n.alt,m=n.oct;void 0===m&&(m=1);var i=n.dir;if(void 0!==r&&(t=r+1+7*m),void 0===t)return null;var u=i<0?"-":"",o="PMMPPMM"[On(t)];return u+t+yn(o,e)},En=function(n){var t=M(n);return t===An?null:t.simple+t.q},Cn=function(n){var t=M(n);if(t===An)return null;var r=(7-t.step)%7,e="P"===t.type?-t.alt:-(t.alt+1);return Dn({step:r,alt:e,oct:t.oct,dir:t.dir})},$n=[1,2,2,3,3,4,5,5,6,6,7,7],Fn="P m M m M P d P m M m M".split(" "),Gn=function(n){var t=n<0?-1:1,r=Math.abs(n),e=r%12,m=Math.floor(r/12);return t*($n[e]+7*m)+Fn[e]},In=Object.freeze({names:hn,tokenize:vn,props:M,num:zn,name:qn,semitones:kn,chroma:Sn,ic:wn,build:Dn,simplify:En,invert:Cn,fromSemitones:Gn}),Tn=[0,2,4,-1,1,3,5],Bn=function(n){return Math.floor(7*n/12)},Nn=Tn.map(Bn),Ln=function(n){var t=n.step,r=n.alt,e=n.oct,m=n.dir;void 0===m&&(m=1);var i=Tn[t]+7*r;return null===e?[m*i]:[m*i,m*(e-Nn[t]-4*r)]},Rn=[3,0,4,1,5,2,6],Un=function(n,t,r){var e=Rn[a(n)],m=Math.floor((n+1)/7);return void 0===t?{step:e,alt:m,dir:r}:{step:e,alt:m,oct:t+4*m+Nn[e],dir:r}},Hn=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}},Jn=function(n){return Hn(function(t){var r=n(t);return null===r.name?null:Ln(r)})},Kn=Jn(L),Qn=Jn(M),Vn=function(n){return 7*n[0]+12*n[1]<0},Wn=function(n){return Vn(n)?Un(-n[0],-n[1],-1):Un(n[0],n[1],1)},Xn=Object.freeze({transpose:l,trFifths:c,fifths:s,transposeBy:f,addIntervals:d,add:p,subtract:b,interval:h,semitones:v}),Yn={chromatic:["1P 2m 2M 3m 3M 4P 4A 5P 6m 6M 7m 7M"],lydian:["1P 2M 3M 4A 5P 6M 7M"],major:["1P 2M 3M 4P 5P 6M 7M",["ionian"]],mixolydian:["1P 2M 3M 4P 5P 6M 7m",["dominant"]],dorian:["1P 2M 3m 4P 5P 6M 7m"],aeolian:["1P 2M 3m 4P 5P 6m 7m",["minor"]],phrygian:["1P 2m 3m 4P 5P 6m 7m"],locrian:["1P 2m 3m 4P 5d 6m 7m"],altered:["1P 2m 3m 3M 5d 6m 7m",["super locrian","diminished whole tone","pomeroy"]],iwato:["1P 2m 4P 5d 7m"],hirajoshi:["1P 2M 3m 5P 6m"],kumoijoshi:["1P 2m 4P 5P 6m"],pelog:["1P 2m 3m 5P 6m"],prometheus:["1P 2M 3M 4A 6M 7m"],ritusen:["1P 2M 4P 5P 6M"],scriabin:["1P 2m 3M 5P 6M"],piongio:["1P 2M 4P 5P 6M 7m"],augmented:["1P 2A 3M 5P 5A 7M"],neopolitan:["1P 2m 3m 4P 5P 6m 7M"],diminished:["1P 2M 3m 4P 5d 6m 6M 7M"],egyptian:["1P 2M 4P 5P 7m"],oriental:["1P 2m 3M 4P 5d 6M 7m"],spanish:["1P 2m 3M 4P 5P 6m 7m",["phrygian major"]],flamenco:["1P 2m 3m 3M 4A 5P 7m"],balinese:["1P 2m 3m 4P 5P 6m 7M"],persian:["1P 2m 3M 4P 5d 6m 7M"],bebop:["1P 2M 3M 4P 5P 6M 7m 7M"],enigmatic:["1P 2m 3M 5d 6m 7m 7M"],ichikosucho:["1P 2M 3M 4P 5d 5P 6M 7M"],"melodic minor":["1P 2M 3m 4P 5P 6M 7M"],"melodic minor second mode":["1P 2m 3m 4P 5P 6M 7m"],"lydian augmented":["1P 2M 3M 4A 5A 6M 7M"],"lydian dominant":["1P 2M 3M 4A 5P 6M 7m",["lydian b7"]],"melodic minor fifth mode":["1P 2M 3M 4P 5P 6m 7m",["hindu","mixolydian b6M"]],"locrian #2":["1P 2M 3m 4P 5d 6m 7m"],"locrian major":["1P 2M 3M 4P 5d 6m 7m",["arabian"]],"major pentatonic":["1P 2M 3M 5P 6M",["pentatonic"]],"lydian pentatonic":["1P 3M 4A 5P 7M",["chinese"]],"mixolydian pentatonic":["1P 3M 4P 5P 7m",["indian"]],"locrian pentatonic":["1P 3m 4P 5d 7m",["minor seven flat five pentatonic"]],"minor pentatonic":["1P 3m 4P 5P 7m"],"minor six pentatonic":["1P 3m 4P 5P 6M"],"minor hexatonic":["1P 2M 3m 4P 5P 7M"],"flat three pentatonic":["1P 2M 3m 5P 6M",["kumoi"]],"flat six pentatonic":["1P 2M 3M 5P 6m"],"major flat two pentatonic":["1P 2m 3M 5P 6M"],"whole tone pentatonic":["1P 3M 5d 6m 7m"],"ionian pentatonic":["1P 3M 4P 5P 7M"],"lydian #5P pentatonic":["1P 3M 4A 5A 7M"],"lydian dominant pentatonic":["1P 3M 4A 5P 7m"],"minor #7M pentatonic":["1P 3m 4P 5P 7M"],"super locrian pentatonic":["1P 3m 4d 5d 7m"],"in-sen":["1P 2m 4P 5P 7m"],"vietnamese 1":["1P 3m 4P 5P 6m"],"vietnamese 2":["1P 3m 4P 5P 7m"],"prometheus neopolitan":["1P 2m 3M 4A 6M 7m"],"major blues":["1P 2M 3m 3M 5P 6M"],"minor blues":["1P 3m 4P 5d 5P 7m",["blues"]],"composite blues":["1P 2M 3m 3M 4P 5d 5P 6M 7m"],"augmented heptatonic":["1P 2A 3M 4P 5P 5A 7M"],"dorian #4":["1P 2M 3m 4A 5P 6M 7m"],"lydian diminished":["1P 2M 3m 4A 5P 6M 7M"],"whole tone":["1P 2M 3M 4A 5A 7m"],"leading whole tone":["1P 2M 3M 4A 5A 7m 7M"],"harmonic minor":["1P 2M 3m 4P 5P 6m 7M"],"lydian minor":["1P 2M 3M 4A 5P 6m 7m"],"neopolitan minor":["1P 2m 3m 4P 5P 6m 7M"],"neopolitan major":["1P 2m 3m 4P 5P 6M 7M",["dorian b2"]],"neopolitan major pentatonic":["1P 3M 4P 5d 7m"],"romanian minor":["1P 2M 3m 5d 5P 6M 7m"],"double harmonic lydian":["1P 2m 3M 4A 5P 6m 7M"],"harmonic major":["1P 2M 3M 4P 5P 6m 7M"],"double harmonic major":["1P 2m 3M 4P 5P 6m 7M",["gypsy"]],"hungarian minor":["1P 2M 3m 4A 5P 6m 7M"],"hungarian major":["1P 2A 3M 4A 5P 6M 7m"],"spanish heptatonic":["1P 2m 3m 3M 4P 5P 6m 7m"],"todi raga":["1P 2m 3m 4A 5P 6m 7M"],"malkos raga":["1P 3m 4P 6m 7m"],"kafi raga":["1P 3m 3M 4P 5P 6M 7m 7M"],"purvi raga":["1P 2m 3M 4P 4A 5P 6m 7M"],"bebop dominant":["1P 2M 3M 4P 5P 6M 7m 7M"],"bebop minor":["1P 2M 3m 3M 4P 5P 6M 7m"],"bebop major":["1P 2M 3M 4P 5P 5A 6M 7M"],"bebop locrian":["1P 2m 3m 4P 5d 5P 6m 7m"],"minor bebop":["1P 2M 3m 4P 5P 6m 7m 7M"],"mystery #1":["1P 2m 3M 5d 6m 7m"],"minor six diminished":["1P 2M 3m 4P 5P 6m 6M 7M"],"ionian augmented":["1P 2M 3M 4P 5A 6M 7M"],"lydian #9":["1P 2m 3M 4A 5P 6M 7M"],"six tone symmetric":["1P 2m 3M 4P 5A 6M"]},Zn={M:["1P 3M 5P",["Major",""]],M13:["1P 3M 5P 7M 9M 13M",["maj13","Maj13"]],M6:["1P 3M 5P 13M",["6"]],M69:["1P 3M 5P 6M 9M",["69"]],M7add13:["1P 3M 5P 6M 7M 9M"],M7b5:["1P 3M 5d 7M"],M7b6:["1P 3M 6m 7M"],M7b9:["1P 3M 5P 7M 9m"],M7sus4:["1P 4P 5P 7M"],M9:["1P 3M 5P 7M 9M",["maj9","Maj9"]],M9b5:["1P 3M 5d 7M 9M"],M9sus4:["1P 4P 5P 7M 9M"],Madd9:["1P 3M 5P 9M",["2","add9","add2"]],Maj7:["1P 3M 5P 7M",["maj7","M7"]],Mb5:["1P 3M 5d"],Mb6:["1P 3M 13m"],Msus2:["1P 2M 5P",["add9no3","sus2"]],Msus4:["1P 4P 5P",["sus","sus4"]],Maddb9:["1P 3M 5P 9m"],m:["1P 3m 5P"],m11:["1P 3m 5P 7m 9M 11P",["_11"]],m11b5:["1P 3m 7m 12d 2M 4P",["h11","_11b5"]],m13:["1P 3m 5P 7m 9M 11P 13M",["_13"]],m6:["1P 3m 4P 5P 13M",["_6"]],m69:["1P 3m 5P 6M 9M",["_69"]],m7:["1P 3m 5P 7m",["minor7","_","_7"]],m7add11:["1P 3m 5P 7m 11P",["m7add4"]],m7b5:["1P 3m 5d 7m",["half-diminished","h7","_7b5"]],m9:["1P 3m 5P 7m 9M",["_9"]],m9b5:["1P 3m 7m 12d 2M",["h9","-9b5"]],mMaj7:["1P 3m 5P 7M",["mM7","_M7"]],mMaj7b6:["1P 3m 5P 6m 7M",["mM7b6"]],mM9:["1P 3m 5P 7M 9M",["mMaj9","-M9"]],mM9b6:["1P 3m 5P 6m 7M 9M",["mMaj9b6"]],mb6M7:["1P 3m 6m 7M"],mb6b9:["1P 3m 6m 9m"],o:["1P 3m 5d",["mb5","dim"]],o7:["1P 3m 5d 13M",["diminished","m6b5","dim7"]],o7M7:["1P 3m 5d 6M 7M"],oM7:["1P 3m 5d 7M"],sus24:["1P 2M 4P 5P",["sus4add9"]],madd4:["1P 3m 4P 5P"],madd9:["1P 3m 5P 9M"],4:["1P 4P 7m 10m",["quartal"]],5:["1P 5P"],7:["1P 3M 5P 7m",["Dominant","Dom"]],9:["1P 3M 5P 7m 9M",["79"]],11:["1P 5P 7m 9M 11P"],13:["1P 3M 5P 7m 9M 13M",["13_"]],64:["5P 8P 10M"],"M#5":["1P 3M 5A",["augmented","maj#5","Maj#5","+","aug"]],"M#5add9":["1P 3M 5A 9M",["+add9"]],"M13#11":["1P 3M 5P 7M 9M 11A 13M",["maj13#11","Maj13#11","M13+4","M13#4"]],"M6#11":["1P 3M 5P 6M 11A",["M6b5","6#11","6b5"]],"M69#11":["1P 3M 5P 6M 9M 11A"],"M7#11":["1P 3M 5P 7M 11A",["maj7#11","Maj7#11","M7+4","M7#4"]],"M7#5":["1P 3M 5A 7M",["maj7#5","Maj7#5","maj9#5","M7+"]],"M7#5sus4":["1P 4P 5A 7M"],"M7#9#11":["1P 3M 5P 7M 9A 11A"],"M9#11":["1P 3M 5P 7M 9M 11A",["maj9#11","Maj9#11","M9+4","M9#4"]],"M9#5":["1P 3M 5A 7M 9M",["Maj9#5"]],"M9#5sus4":["1P 4P 5A 7M 9M"],"11b9":["1P 5P 7m 9m 11P"],"13#11":["1P 3M 5P 7m 9M 11A 13M",["13+4","13#4"]],"13#9":["1P 3M 5P 7m 9A 13M",["13#9_"]],"13#9#11":["1P 3M 5P 7m 9A 11A 13M"],"13b5":["1P 3M 5d 6M 7m 9M"],"13b9":["1P 3M 5P 7m 9m 13M"],"13b9#11":["1P 3M 5P 7m 9m 11A 13M"],"13no5":["1P 3M 7m 9M 13M"],"13sus4":["1P 4P 5P 7m 9M 13M",["13sus"]],"69#11":["1P 3M 5P 6M 9M 11A"],"7#11":["1P 3M 5P 7m 11A",["7+4","7#4","7#11_","7#4_"]],"7#11b13":["1P 3M 5P 7m 11A 13m",["7b5b13"]],"7#5":["1P 3M 5A 7m",["+7","7aug","aug7"]],"7#5#9":["1P 3M 5A 7m 9A",["7alt","7#5#9_","7#9b13_"]],"7#5b9":["1P 3M 5A 7m 9m"],"7#5b9#11":["1P 3M 5A 7m 9m 11A"],"7#5sus4":["1P 4P 5A 7m"],"7#9":["1P 3M 5P 7m 9A",["7#9_"]],"7#9#11":["1P 3M 5P 7m 9A 11A",["7b5#9"]],"7#9#11b13":["1P 3M 5P 7m 9A 11A 13m"],"7#9b13":["1P 3M 5P 7m 9A 13m"],"7add6":["1P 3M 5P 7m 13M",["67","7add13"]],"7b13":["1P 3M 7m 13m"],"7b5":["1P 3M 5d 7m"],"7b6":["1P 3M 5P 6m 7m"],"7b9":["1P 3M 5P 7m 9m"],"7b9#11":["1P 3M 5P 7m 9m 11A",["7b5b9"]],"7b9#9":["1P 3M 5P 7m 9m 9A"],"7b9b13":["1P 3M 5P 7m 9m 13m"],"7b9b13#11":["1P 3M 5P 7m 9m 11A 13m",["7b9#11b13","7b5b9b13"]],"7no5":["1P 3M 7m"],"7sus4":["1P 4P 5P 7m",["7sus"]],"7sus4b9":["1P 4P 5P 7m 9m",["susb9","7susb9","7b9sus","7b9sus4","phryg"]],"7sus4b9b13":["1P 4P 5P 7m 9m 13m",["7b9b13sus4"]],"9#11":["1P 3M 5P 7m 9M 11A",["9+4","9#4","9#11_","9#4_"]],"9#11b13":["1P 3M 5P 7m 9M 11A 13m",["9b5b13"]],"9#5":["1P 3M 5A 7m 9M",["9+"]],"9#5#11":["1P 3M 5A 7m 9M 11A"],"9b13":["1P 3M 7m 9M 13m"],"9b5":["1P 3M 5d 7m 9M"],"9no5":["1P 3M 7m 9M"],"9sus4":["1P 4P 5P 7m 9M",["9sus"]],"m#5":["1P 3m 5A",["m+","mb6"]],"m11A 5":["1P 3m 6m 7m 9M 11P"],"m7#5":["1P 3m 6m 7m"],"m9#5":["1P 3m 6m 7m 9M"],"+add#9":["1P 3M 5A 9A"]},nt=function(n){return X(n)||Sn(n)||0},tt=function(n){return parseInt(A(n),2)},rt=function(n){return n.replace(/0/g,"").length},et=null,mt=/^[01]{12}$/,it="1P 2m 2M 3m 3M 4P 5d 5P 6m 6M 7m 7M".split(" "),ut=Object.freeze({chroma:A,chromas:g,modes:j,isChroma:y,intervals:O,isEqual:x,isSubsetOf:_,isSupersetOf:z,includes:q,filter:k}),ot=function(n){var t=Object.keys(n).sort(),r=[],e=[],m=function(n,t,m){r[n]=t,e[m]=e[m]||[],e[m].push(n)};t.forEach(function(t){var r=n[t][0].split(" "),e=n[t][1],i=A(r);m(t,r,i),e&&e.forEach(function(n){return m(n,r,i)})});var i=Object.keys(r).sort(),u=function(n){return r[n]};return u.names=function(n){return"string"==typeof n?(e[n]||[]).slice():(!0===n?i:t).slice()},u},Pt=function(n,t){var r=function(r){return n(r)||t(r)};return r.names=function(r){return n.names(r).concat(t.names(r))},r},Mt=ot(Yn),at=ot(Zn),lt=Pt(Mt,at),ct=Object.freeze({dictionary:ot,combine:Pt,scale:Mt,chord:at,pcset:lt}),st=Object.freeze({name:null,intervals:[],names:[],chroma:null,setnum:null}),ft=function(n,t){return function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=Mt(n);if(!t)return st;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=Mt.names(r.chroma),Object.freeze(r)},{}),dt=Mt.names,pt=function(n){var t=D(n);return ft(t[1]).intervals},bt=function(n){var t=pt(n),r=S(n);return j(t).map(function(n,e){var m=Mt.names(n)[0];if(m)return[r[e]||t[e],m]}).filter(function(n){return n})},ht=function(n){var t=_(pt(n));return at.names().filter(function(n){return t(at(n))})},vt=function(n){var t=Mn(n.map(U));if(!t.length)return t;var r=t[0],e=P(t);return u(e.indexOf(r),e)},At=function(n){if(!pt(n).length)return[];var t=z(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},gt=function(n){var t=_(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},jt=Object.freeze({props:ft,names:dt,intervals:pt,notes:S,exists:w,tokenize:D,modeNames:bt,chords:ht,toScale:vt,supersets:At,subsets:gt}),yt=at.names,Ot=Object.freeze({name:null,names:[],intervals:[],chroma:null,setnum:null}),xt=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=at(n);if(!t)return Ot;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=at.names(r.chroma),r}),_t=function(n){return xt(C(n)[1]).intervals},zt=function(n){return void 0!==at(C(n)[1])},qt=function(n){if(!_t(n).length)return[];var t=z(_t(n));return at.names().filter(function(n){return t(at(n))})},kt=function(n){var t=_(_t(n));return at.names().filter(function(n){return t(at(n))})},St=/^(6|64|7|9|11|13)$/,wt=Object.freeze({names:yt,props:xt,intervals:_t,notes:E,exists:zt,supersets:qt,subsets:kt,tokenize:C}),Dt=l,Et=h,Ct=L,$t=H,Ft=K,Gt=at,It=Mt;n.Array=sn,n.Note=Pn,n.Interval=In,n.Distance=Xn,n.Scale=jt,n.Chord=wt,n.PcSet=ut,n.Dictionary=ct,n.transpose=Dt,n.interval=Et,n.note=Ct,n.midi=$t,n.freq=Ft,n.chord=Gt,n.scale=It,Object.defineProperty(n,"__esModule",{value:!0})});
2 | //# sourceMappingURL=tonal.min.js.map
3 |
--------------------------------------------------------------------------------
/public/sqcr-demo/main.js:
--------------------------------------------------------------------------------
1 | // DATA container
2 | let data = [];
3 |
4 |
5 | // OSC.js stuff
6 | const handleMessage = (msg) => {
7 | // console.log('MSG', msg);
8 | data = msg.address.split('/');
9 | }
10 |
11 | const initOSC = () => {
12 | // Init container
13 |
14 | // Init port
15 | oscPort = new osc.WebSocketPort({
16 | url: "ws://localhost:8081"
17 | });
18 |
19 |
20 | // listen
21 | oscPort.on('message', (msg) => {
22 | handleMessage(msg); // Debugging
23 | });
24 |
25 | // open port
26 | oscPort.open();
27 | };
28 |
29 | // used later to start OSC
30 | window.initOSC = initOSC();
31 |
32 | // Additional code below
33 |
--------------------------------------------------------------------------------
/public/sqcr-demo/md/generative-hip-hop-slides.md:
--------------------------------------------------------------------------------
1 | class: center, middle
2 | iframeURL: /public/sqcr-demo/html/808.html
3 | iframeSelector: .frame-808-1
4 |
5 | # Making Self-Generating Hip Hop in JS
6 |
7 |
8 |
9 | ???
10 | Sound check. Reset clock before starting.
11 |
12 | ---
13 |
14 | class: center, middle
15 |
16 | # Who Am I?
17 |
18 | ---
19 |
20 | # Who Am I?
21 |
22 | --
23 |
24 | - I'm **[omar delarosa](https://omardelarosa.com)**.
25 |
26 | --
27 |
28 | - I'm a Lead Software Engineer at Grubhub Seamless. (We're hiring.)
29 |
30 | --
31 |
32 | - I play music in my spare time.
33 |
34 | ---
35 |
36 | class: center, middle
37 |
38 | # What is Music?
39 |
40 | ---
41 |
42 | class: center, middle
43 |
44 | ## Organized Sound Waves
45 |
46 |
47 |
48 | ---
49 |
50 | class: center, middle
51 |
52 | ### One Way To Do Music Randomly...
53 |
54 | ---
55 |
56 | class: center, middle
57 | iframeURL: /public/sqcr-demo/html/random-tones.html
58 | iframeSelector: .random-tones-frame
59 |
60 | ### Random Tone Frequencies
61 |
62 |
63 |
64 | ---
65 |
66 | class: center, middle
67 |
68 | ### Yuck.
69 |
70 | ---
71 |
72 | class: center, middle
73 |
74 | ## Can We Do Better?
75 |
76 | ---
77 |
78 | class: center, middle
79 |
80 | iframeURL: /public/sqcr-demo/html/scale-tones.html
81 | iframeSelector: .scale-tones-frame
82 |
83 | ### Random Tones from a Scale
84 |
85 |
86 |
87 | ???
88 | Avoid talking over synths
89 |
90 | ---
91 |
92 | class: center, middle
93 |
94 | ### Better.
95 |
96 | ---
97 |
98 | class: center, middle
99 |
100 | ### We can do better yet.
101 |
102 | ---
103 |
104 | class: center, middle
105 |
106 | ### By Using _Markov Chains_
107 |
108 | ---
109 |
110 | class: center, middle
111 |
112 | # Markov Chain
113 |
114 | 
115 |
116 | _A Markov chain is "a stochastic model describing a sequence of possible events in which the probability of each event depends only on the state attained in the previous event"_
117 |
118 | [from Wikipedia](https://en.wikipedia.org/wiki/Markov_chain)
119 |
120 | ---
121 |
122 | class: center, top
123 | iframeURL: /public/sqcr-demo/html/notes-graph.html
124 | iframeSelector: .scale-tones-graph-frame
125 |
126 | #### Markov Chaining of Tones in a Scale
127 |
128 |
129 |
130 | ???
131 | Avoid talking over synths
132 |
133 | ---
134 |
135 | # Markov Chain
136 |
137 | - Is like a state machine for gamblers
138 |
139 | --
140 |
141 | - Markov chain models can be "generated" ML-style from a corpus text (or a MIDI file)
142 |
143 | --
144 |
145 | - Data can be represented and stored easily as structured data formats such as JSON
146 |
147 | ---
148 |
149 | class: center, middle
150 |
151 | ## Slide Scope Creep
152 |
153 | #### (Not what this talk is about)
154 |
155 | ---
156 |
157 | class: center, middle
158 | iframeURL: /public/sqcr-demo/html/808.html
159 | iframeSelector: .frame-808-geez
160 |
161 | ## What Does This Have To Do With Hip Hop?
162 |
163 |
164 |
165 | ---
166 |
167 | class: middle, center
168 |
169 | # Rhythm, Harmony and Computation:
170 |
171 | #### A Brief History
172 |
173 | ---
174 |
175 | class: center, middle
176 |
177 | # 2000 B.C. to 1980s:
178 |
179 | ### Harmony, Rhythm and Music Theory:
180 |
181 | ---
182 |
183 | ### Harmony
184 |
185 | --
186 |
187 | - **tone** - a unit of sound (aka a **note**)
188 |
189 | --
190 |
191 | - **scale** - a ranked _Set_ of pitched tones
192 |
193 | --
194 |
195 | - **melody** - a sequence of tones over time
196 |
197 | ---
198 |
199 | ### Harmony
200 |
201 | --
202 |
203 | - **chord** - a group of tones played in (or close to) unison
204 |
205 | --
206 |
207 | - **progression** - a sequence of chords over time
208 |
209 | ---
210 |
211 | ### Rhythm
212 |
213 | - **beat** - a single unit of rhythm
214 |
215 | - **measure** - a regularly spaced group of beats
216 |
217 | - **duration** - how long a tone lasts
218 |
219 | ---
220 |
221 | ### Rhythm & Durations as Fractions
222 |
223 | - Durations are all described as fractions of a **measure**
224 |
225 | --
226 |
227 | - **1/4** Note
228 |
229 | --
230 |
231 | - **1/8** Note
232 |
233 | --
234 |
235 | - **1/16** Note
236 |
237 | ---
238 |
239 | ### Durations as Fractions
240 |
241 | - Not all are multiples of 2.
242 |
243 | --
244 |
245 | - Some interesting things happen when you mix up durations where the denominator of the fraction is a multiple of 3.
246 |
247 |
248 |
249 | --
250 |
251 | - This is common in hip hop beats.
252 |
253 | ---
254 |
255 | class: middle, center
256 |
257 | # 1980s to Now
258 |
259 | ### Rhythm and Computation
260 |
261 | ---
262 |
263 | iframeURL: /public/sqcr-demo/html/808.html
264 | iframeSelector: .frame-808
265 |
266 | ### Roland TR-808
267 |
268 | #### The classic drum machine of hip hop
269 |
270 |
271 |
272 | ---
273 |
274 | class: middle, center
275 | iframeURL: /public/sqcr-demo/html/akai.html
276 | iframeSelector: .frame-akai
277 |
278 | ### Akai MPC-2000XL
279 |
280 | #### A classic sampler for hip hop production
281 |
282 |
283 |
284 | ---
285 |
286 | # Rhythm and Computation
287 |
288 | #### Beat Grids
289 |
290 | 
291 |
292 | - Centered around 1/16th note ticks
293 |
294 | - Can be difficult to "escape the grid" with durations < 1/16.
295 |
296 | - Also tough to use subdivisions that are multiples of 3.
297 |
298 | ---
299 |
300 | # Rhythm and Computation
301 |
302 | #### Beat Grids as Code
303 |
304 | ```javascript
305 | // 16-element arrays can represent rhythm patterns, but are tough to read.
306 | const kicks = [1,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; // prettier-ignore
307 | const snares = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; // prettier-ignore
308 | const hats = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; // prettier-ignore
309 | const cowbell = [0,0,0,0, 0,0,0,0, 0,0,0,0, 1,0,1,0]; // prettier-ignore
310 | ```
311 |
312 | ---
313 |
314 | # Rhythm Notation
315 |
316 | #### Beat Grids as "Words"
317 |
318 | ```javascript
319 | // Easier to read, CPU-trivial preprocessing
320 | const kicks = fmt('1010 0010 0010 0010'); // prettier-ignore
321 | const snares = fmt('0000 1000 0000 1000'); // prettier-ignore
322 | const hats = fmt('1111 1111 1111 1111'); // prettier-ignore
323 | const cowbell = fmt('0000 0000 0000 01010'); // prettier-ignore
324 | ```
325 |
326 | ---
327 |
328 | # Rhythm Notation
329 |
330 | #### Beat Grids as Lists of Words (a Language?)
331 |
332 | ```javascript
333 | // A list of patterns
334 | const kick_patterns = [
335 | fmt('1010 0010 0010 0010'),
336 | fmt('1001 0001 0101 0010'),
337 | fmt('1000 0101 0100 0010'),
338 | fmt('1000 0010 0000 0100'),
339 | ];
340 | ```
341 |
342 | ---
343 |
344 | ## Generative Beats
345 |
346 | #### We could make two pattern sets
347 |
348 | ```javascript
349 | const kick_patterns = [
350 | fmt('1010 0010 0010 0010'),
351 | fmt('1001 0001 0101 0010'),
352 | fmt('1000 0101 0100 0010'),
353 | fmt('1000 0010 0000 0100'),
354 | ];
355 |
356 | const snare_patterns = [
357 | fmt('0000 1000 0000 1000'),
358 | fmt('0010 1000 0000 1010'),
359 | fmt('0000 1000 0010 1000'),
360 | ];
361 | ```
362 |
363 | ---
364 |
365 | ## Generative Beats
366 |
367 | #### And randomly combine them
368 |
369 | ```javascript
370 | const kicks_sequence = [
371 | ..._.sample(kick_patterns),
372 | ..._.sample(kick_patterns),
373 | ..._.sample(kick_patterns),
374 | ..._.sample(kick_patterns),
375 | ];
376 |
377 | const snare_sequence = [
378 | ..._.sample(snare_patterns),
379 | ..._.sample(snare_patterns),
380 | ..._.sample(snare_patterns),
381 | ..._.sample(snare_patterns),
382 | ];
383 |
384 | playParallel(kicks_sequence, snare_sequence);
385 | ```
386 |
387 | ---
388 |
389 | class: center, middle
390 |
391 | # Or we can do better with Markov Chains
392 |
393 | 
394 |
395 | ---
396 |
397 | class: center, top
398 | iframeURL: /public/sqcr-demo/html/notes-graph.html
399 | iframeSelector: .scale-tones-graph-frame2
400 |
401 | #### Markov Chaining of Tones in a Scale
402 |
403 |
404 |
405 | ???
406 | Avoid talking over synths
407 |
408 | ---
409 |
410 | class: center, top
411 | iframeURL: /public/sqcr-demo/html/chords-graph.html
412 | iframeSelector: .scale-chords-graph-frame
413 |
414 | #### Markov Chaining of Chords in a Scale
415 |
416 |
417 |
418 | ???
419 | Avoid talking over synths
420 |
421 | ---
422 |
423 | class: center, top
424 | iframeURL: /public/sqcr-demo/html/beats-graph.html
425 | iframeSelector: .beats-graph-frame
426 |
427 | #### Markov Chaining of Beat Durations
428 |
429 |
430 |
431 | ---
432 |
433 | ### Simple Markov Chain Implementation
434 |
435 | ```javascript
436 | class MarkovChain {
437 | constructor(obj = {}, states = [], initialState = 0) {
438 | this.graph = { ...obj };
439 | this.states = [...states];
440 | this.currentState = initialState;
441 | }
442 |
443 | set() {
444 | const newState = this.sample(this.graph[this.currentState]);
445 | this.currentState = newState;
446 | }
447 |
448 | next() {
449 | this.set();
450 | return this.states[this.currentState];
451 | }
452 |
453 | sample(list) {
454 | return list[Math.floor(list.length * Math.random())];
455 | }
456 | }
457 | ```
458 |
459 | ---
460 |
461 | ## Markov Chain of Notes
462 |
463 | - Using an adjacency list instead of matrix (for readability, simplicity)
464 |
465 | ```javascript
466 | const NOTES = ['C', 'D', 'E', 'F', 'G', 'A', 'B'];
467 |
468 | const G = {
469 | // Repeated notes represent higher probabilities
470 | '0': [1, 1, 0, 3, 4, 5, 6], // 0 -> 1 is 2/7, the rest 1/7
471 | '1': [0, 0, 2, 3], // 1 -> 0 is 1/2 the others 1/4
472 | '2': [1, 3, 4],
473 | '3': [4], // 3 -> 4 means state 4 always follows 3 or 1/1 probability
474 | '4': [5],
475 | '5': [5, 4, 1, 0],
476 | '6': [2, 2, 2, 3, 3],
477 | };
478 |
479 | const mc = new MarkovChain(G, NOTES);
480 | ```
481 |
482 | ---
483 |
484 | ## Markov Chain of Chords
485 |
486 | ```javascript
487 | const CHORDS = ['C maj', 'D min', 'E min', 'F maj', 'G maj', 'A min', 'B dim'];
488 |
489 | // Favors I <-> IV, V -> I cadences
490 | const G = {
491 | '0': [3, 3, 3, 5],
492 | '1': [2, 5],
493 | '2': [3],
494 | '3': [4, 4, 4, 1, 1],
495 | '4': [0, 0, 0, 5],
496 | '5': [1, 6],
497 | '6': [4],
498 | };
499 |
500 | const mc = new MarkovChain(G, CHORDS);
501 | ```
502 |
503 | ---
504 |
505 | ## Markov Chain of Rhythm Patterns
506 |
507 | ```javascript
508 | const M = 96; // MIDI Ticks in a measure
509 |
510 | const HATS = [
511 | [M / 16, 4],
512 | [M / 12, 3],
513 | [M / 24, 6],
514 | [M / 32, 4],
515 | [M / 48, 6],
516 | [M / 64, 8],
517 | ];
518 |
519 | // Favors steady 1/16 notes -- common in hip hop
520 | const G = {
521 | '0': [0, 0, 0, 0, 0, 0, 1, 2, 3, 4], // 0 -> 0 has 3/5 odds
522 | '1': [0, 0, 0, 3],
523 | '2': [0, 0, 0, 3],
524 | '3': [2, 5],
525 | '4': [2, 3, 4, 1],
526 | '5': [3, 2, 4, 2, 2],
527 | };
528 | ```
529 |
530 | ---
531 |
532 | # And So...
533 |
534 | - Tones, Melodies Chords, Beats, Measures, etc. can be thought of as "states" in a markov chin
535 |
536 | --
537 |
538 | - This can create more natural sounding compositions than brute force randomization.
539 |
540 | --
541 |
542 | - `MarkovChain` is a data model and thus framework/library agnostic.
543 |
544 | ---
545 |
546 | iframeURL: /public/sqcr-demo/html/matrix-16x8.html
547 | iframeSelector: .matrix-16x8
548 |
549 | ### Thanks
550 |
551 |
552 |
553 | - [Tone.js - full features JS code library](https://tonejs.github.io/)
554 | - [vis.js - dataviz library](http://visjs.org/)
555 | - [sqcr - a JS sequencer server I made to run some of the code in these slides](https://github.com/omardelarosa/sqcr)
556 | - [Chris Wilson - "A Tale of Two Clocks"](https://www.html5rocks.com/en/tutorials/audio/scheduling/#toc-usingsettimeout)
557 | - [Andrew Sorensen - "The Concert Programmer"](https://www.youtube.com/watch?v=yY1FSsUV-8c)
558 | - [Sam Aaron - "Programming as Performance"](https://www.youtube.com/watch?v=TK1mBqKvIyU)
559 |
--------------------------------------------------------------------------------
/public/sqcr-demo/renderers/matrix-renderer.js:
--------------------------------------------------------------------------------
1 | const makeRow = (cols, idx = 1) => {
2 | const colDivs = [];
3 |
4 | for (let i = 0; i < cols; i++) {
5 | colDivs.push(
6 | ``,
7 | );
8 | }
9 |
10 | return `${colDivs.join('\n')}
`;
11 | };
12 |
13 | const makeVideoPlayer = () => `
14 |
15 |
16 |
17 | `;
18 |
19 | const makeGrid = (rows, cols) => {
20 | const rowsHTML = [];
21 |
22 | for (let i = 0; i < rows; i++) {
23 | rowsHTML.push(makeRow(cols, i + 1));
24 | }
25 |
26 | return `${rowsHTML.join('\n')}
`;
27 | };
28 |
29 | module.exports = (locals, scripts, scriptTags) => `
30 |
31 |
32 |
33 | Untitled - osc.js demo
34 |
35 |
36 |
37 |
38 |
39 |
40 | ${scriptTags.join('\n')}
41 |
42 |
43 |
44 | ${'' && makeVideoPlayer()}
45 | ${makeGrid(8, 16)}
46 |
50 |
51 |
52 |
53 | `;
54 |
--------------------------------------------------------------------------------
/public/sqcr-demo/renderers/slider.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 |
4 | const getMarkdown = pathToMarkdown => {
5 | const absPath = path.join(process.cwd(), pathToMarkdown);
6 | try {
7 | return fs.readFileSync(absPath).toString();
8 | } catch (e) {
9 | console.error('Markdown read error: ', e.message);
10 | return '';
11 | }
12 | };
13 |
14 | module.exports = (locals, scripts, scriptTags) => `
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 | `;
30 |
--------------------------------------------------------------------------------
/public/sqcr-demo/sqcr-setup.js:
--------------------------------------------------------------------------------
1 | // SQCR.OSC = osc;
2 | // SQCR.MIDI = WebMidi;
3 |
4 | // sqcr = new SQCR();
5 |
6 | function sqcrToggle() {
7 | if (sqcr.hasStopped) {
8 | sqcr.start();
9 | } else {
10 | sqcr.stop();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/public/sqcr-demo/styles.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Color Pallette:
3 | * 1 - #ccfa99
4 | * 2 - #faf099
5 | * 3 - #99f0fa
6 | * 4 - #fa99f0
7 | * 5 - #cc99fa
8 | *
9 | */
10 |
11 | div {
12 | min-height: 15px;
13 | }
14 |
15 | html,
16 | body,
17 | div {
18 | background-color: #fa99f0;
19 | }
20 |
21 | .k-col {
22 | height: 15px;
23 | }
24 |
25 | .icon-link {
26 | text-decoration: none;
27 | }
28 |
29 | .colorize {
30 | background-color: #faf099;
31 | }
32 |
33 | .colorize-0 {
34 | background-color: #ff0086;
35 | }
36 |
37 | .colorize-1 {
38 | background-color: #ccfa99;
39 | }
40 |
41 | .colorize-2 {
42 | background-color: #faf099;
43 | }
44 |
45 | .colorize-3 {
46 | background-color: #99f0fa;
47 | }
48 |
49 | .colorize-4 {
50 | background-color: #fa99f0;
51 | /* filter: blur(2px); */
52 | }
53 |
54 | .colorize-1.colorize-3 {
55 | background-color: #ff7900;
56 | }
57 |
58 | .colorize-2.colorize-3 {
59 | background-color: #39ff14;
60 | }
61 |
62 | .colorize-4.colorize-1 {
63 | background-color: #99f0fa;
64 | }
65 |
66 | .colorize-2.colorize-1 {
67 | background-color: #ff7900;
68 | }
69 |
--------------------------------------------------------------------------------
/public/sqcr-demo/visualizer.js:
--------------------------------------------------------------------------------
1 | let oscPort = {};
2 |
3 | const handleMessage = msg => {
4 | console.log('message', msg);
5 | };
6 |
7 | const LightEvent = data => new CustomEvent('light', { detail: data });
8 |
9 | const elementMatrix = [];
10 |
11 | const mget = (mat, x, y) => {
12 | return (mat[x] && mat[x][y]) || undefined;
13 | };
14 |
15 | const MAX_COLS = 16;
16 | const MAX_ROWS = 8;
17 |
18 | const blink = (el, dur = 100, color) => {
19 | const colorClass = `colorize-${color}`;
20 | // TODO: add random color
21 | el.classList.add(colorClass);
22 |
23 | setTimeout(() => {
24 | el.classList.remove(colorClass);
25 | }, dur);
26 | };
27 |
28 | // For debugging purposes.
29 | const ticker = () => {
30 | let n = 0;
31 | let m = 0;
32 |
33 | return e => {
34 | const el = elementMatrix[n][m];
35 | blink(el);
36 | m++;
37 | if (m >= MAX_COLS) {
38 | m = 0;
39 | n++;
40 | }
41 |
42 | if (n >= MAX_ROWS) {
43 | n = 0;
44 | }
45 | };
46 | };
47 |
48 | const initViz = () => {
49 | // Init container
50 | const $container = document.querySelector('.container');
51 |
52 | const $rows = document.querySelectorAll('.k-row');
53 |
54 | // TODO: make this more widely compatible and avoid .forEach
55 | $rows.forEach($row => {
56 | const rowRefs = [];
57 | $row.querySelectorAll('.k-col').forEach($cell => {
58 | rowRefs.push($cell);
59 | });
60 | elementMatrix.push(rowRefs);
61 | });
62 |
63 | $container.addEventListener('light', e => {
64 | const detail = e.detail || {};
65 | const { address = '', args = [] } = detail;
66 | const addressParts = address.split('/');
67 | if (addressParts[1] === 'blink') {
68 | const [, , m, n, color, dur] = addressParts;
69 | const mNum = Number(m);
70 | const nNum = Number(n);
71 | const el = mget(elementMatrix, mNum, nNum);
72 | el && blink(el, parseInt(dur), color);
73 | }
74 | });
75 |
76 | window.Visualizer = {
77 | el: $container,
78 |
79 | blink: msg => {
80 | $container.dispatchEvent(LightEvent({ address: msg }));
81 | },
82 | };
83 | };
84 |
85 | window.initViz = initViz;
86 |
--------------------------------------------------------------------------------
/src/Markov.js:
--------------------------------------------------------------------------------
1 | class MarkovChain {
2 | constructor(obj = {}, states = [], initialState = 0) {
3 | this.graph = { ...obj };
4 | this.states = [...states];
5 | this.currentState = initialState;
6 | }
7 |
8 | /**
9 | *
10 | * Checks current state value without changing it.
11 | *
12 | */
13 | peek() {
14 | return this.states[this.currentState];
15 | }
16 |
17 | /**
18 | *
19 | * Checks the id of the current state
20 | *
21 | */
22 | peekID() {
23 | return this.currentState;
24 | }
25 |
26 | /**
27 | *
28 | * Sets next state
29 | *
30 | */
31 |
32 | set() {
33 | const newState = this.sample(this.graph[this.currentState]);
34 | this.currentState = newState;
35 | }
36 |
37 | /**
38 | *
39 | * Sets and returns next state in chain
40 | *
41 | */
42 | next() {
43 | this.set();
44 | return this.states[this.currentState];
45 | }
46 | /**
47 | *
48 | * Sets and returns ID of next state in chain
49 | *
50 | */
51 | nextID() {
52 | this.set();
53 | return this.currentState;
54 | }
55 |
56 | /**
57 | *
58 | * Gets random element from a list
59 | *
60 | */
61 | sample(list) {
62 | return list[Math.floor(list.length * Math.random())];
63 | }
64 | }
65 |
--------------------------------------------------------------------------------