diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 000000000..259748a14 --- /dev/null +++ b/server/.gitignore @@ -0,0 +1 @@ +samples/old \ No newline at end of file diff --git a/server/headline.js b/server/headline.js new file mode 100644 index 000000000..ae50f8ee4 --- /dev/null +++ b/server/headline.js @@ -0,0 +1,24 @@ +const headlines = [ + ` + ██████ ▄▄▄█████▓ ██▀███ █ ██ ▓█████▄ ▓█████ ██▓ +▒██ ▒ ▓ ██▒ ▓▒▓██ ▒ ██▒ ██ ▓██▒▒██▀ ██▌▓█ ▀ ▓██▒ +░ ▓██▄ ▒ ▓██░ ▒░▓██ ░▄█ ▒▓██ ▒██░░██ █▌▒███ ▒██░ + ▒ ██▒░ ▓██▓ ░ ▒██▀▀█▄ ▓▓█ ░██░░▓█▄ ▌▒▓█ ▄ ▒██░ +▒██████▒▒ ▒██▒ ░ ░██▓ ▒██▒▒▒█████▓ ░▒████▓ ░▒████▒░██████▒ +▒ ▒▓▒ ▒ ░ ▒ ░░ ░ ▒▓ ░▒▓░░▒▓▒ ▒ ▒ ▒▒▓ ▒ ░░ ▒░ ░░ ▒░▓ ░ +░ ░▒ ░ ░ ░ ░▒ ░ ▒░░░▒░ ░ ░ ░ ▒ ▒ ░ ░ ░░ ░ ▒ ░ +░ ░ ░ ░ ░░ ░ ░░░ ░ ░ ░ ░ ░ ░ ░ ░ + ░ ░ ░ ░ ░ ░ ░ ░ + ░ `, + ` + + ███████╗████████╗██████╗ ██╗ ██╗██████╗ ███████╗██╗ + ██╔════╝╚══██╔══╝██╔══██╗██║ ██║██╔══██╗██╔════╝██║ + ███████╗ ██║ ██████╔╝██║ ██║██║ ██║█████╗ ██║ + ╚════██║ ██║ ██╔══██╗██║ ██║██║ ██║██╔══╝ ██║ + ███████║ ██║ ██║ ██║╚██████╔╝██████╔╝███████╗███████╗ + ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝ +`, +]; + +export const randomHeadline = () => headlines[Math.floor(Math.random() * headlines.length)]; diff --git a/server/package-lock.json b/server/package-lock.json new file mode 100644 index 000000000..3e069342b --- /dev/null +++ b/server/package-lock.json @@ -0,0 +1,677 @@ +{ + "name": "@strudel.cycles/server", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@strudel.cycles/server", + "version": "0.0.1", + "license": "ISC", + "dependencies": { + "speaker": "^0.5.4", + "web-audio-api": "^0.2.2" + } + }, + "node_modules/aac": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/aac/-/aac-0.1.3.tgz", + "integrity": "sha512-mhkqrzCOMndmoQovW43ry8tkMttuvKcpU0u9/K7zI+lF5NtCY2NE+HwAPiEgd3rHK7IuBT1ZsGL+LKeCPW9btQ==", + "peerDependencies": { + "av": "~0.4.0" + } + }, + "node_modules/abc": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/abc/-/abc-0.5.1.tgz", + "integrity": "sha512-WRBP9wjuEdmzw1yFHCVf7Qp/PXSmfuUSX3FSs+5+uLG4qGKmhOPKl8LtZaG0p6xxuB6hX1tIzH4VaHL23+bU5A==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/alac": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/alac/-/alac-0.1.0.tgz", + "integrity": "sha512-+NBR/Nj/5zndHO7Oz4EOE7Qj+v+hk/0edJerBhjMQRznyjfaYV6/W+tUOOlLTZ0BWWD4p6eb11KKDHoPW5LsCw==", + "peerDependencies": { + "av": "~0.4.0" + } + }, + "node_modules/assertion-error": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.0.tgz", + "integrity": "sha512-g/gZV+G476cnmtYI+Ko9d5khxSoCSoom/EaNmmCfwpOvBXEJ18qwFrxfP1/CsIqk2no1sAKKwxndV0tP7ROOFQ==", + "engines": { + "node": "*" + } + }, + "node_modules/async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==" + }, + "node_modules/audiobuffer": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/audiobuffer/-/audiobuffer-0.2.0.tgz", + "integrity": "sha512-wEZ3iAOK1yNCy1PNcSe2V1pzzCV5rezYg0r/TRwojZBIVupQF56ioI0x5PGgatmWxJ4t8sWXymg8AFfopPXfrg==", + "dependencies": { + "underscore": "1.4.x" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/audiobuffer/node_modules/underscore": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", + "integrity": "sha512-ZqGrAgaqqZM7LGRzNjLnw5elevWb5M8LEoDMadxIW3OWbcv72wMMgKdwOKpd5Fqxe8choLD8HN3iSj3TUh/giQ==" + }, + "node_modules/av": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/av/-/av-0.4.9.tgz", + "integrity": "sha512-MvkT0k+co6o+zLMrBFFeVhYcG/S/jzy+2p00c/VwA71q6g90J28qUNh93NabKrcN06bkwFK0OeiEpFsQd7TS7g==", + "dependencies": { + "coffeeify": "^0.6.0" + }, + "optionalDependencies": { + "speaker": "^0.3.0" + } + }, + "node_modules/av/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "optional": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/av/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "optional": true + }, + "node_modules/av/node_modules/speaker": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/speaker/-/speaker-0.3.1.tgz", + "integrity": "sha512-LEqSy+FHYHPZj4kX8NHylzaOmy+VIqj57enm2GS4B568hj0SdKDYa9jALCGQy43LZa/JmQk1iF0nlMVbS1PfPg==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "bindings": "^1.2.1", + "debug": "^2.2.0", + "nan": "^2.2.0", + "readable-stream": "^2.0.5" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==" + }, + "node_modules/chai": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-1.7.2.tgz", + "integrity": "sha512-iTItmoMR+S+g8g0xU7db2mrr2LeLMJ6Y+YJwJEOUSaVTzm6qyTBfj5r+5x+XQhlXUfVn6WfFS4sXpEtMg6Qwaw==", + "dependencies": { + "assertion-error": "1.0.0" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/coffee-script": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.7.1.tgz", + "integrity": "sha512-W3s+SROY73OmrSGtPTTW/2wp2rmW5vuh0/tUuCK1NvTuyzLOVPccIP9whmhZ4cYWcr2NJPNENZIFaAMkTD5G3w==", + "deprecated": "CoffeeScript on NPM has moved to \"coffeescript\" (no hyphen)", + "dependencies": { + "mkdirp": "~0.3.5" + }, + "bin": { + "cake": "bin/cake", + "coffee": "bin/coffee" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/coffeeify": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/coffeeify/-/coffeeify-0.6.0.tgz", + "integrity": "sha512-nt2rZwyeqLnzdbC15ZUBnQtokHLqNnbgfpUMYzAk1Pa33hObdtXnDV0SmTj2DWbzp47MpR87ix3uKHyutnzjsg==", + "dependencies": { + "coffee-script": "~1.7.0", + "convert-source-map": "~0.3.3", + "through": "~2.3.4" + } + }, + "node_modules/convert-source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", + "integrity": "sha512-+4nRk0k3oEpwUB7/CalD7xE2z4VmtEnnq0GO2IPTkrooTrAhEsWvuLF5iWP1dXrwluki/azwXV1ve7gtYuPldg==" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "optional": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "node_modules/flac": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/flac/-/flac-0.3.0.tgz", + "integrity": "sha512-52oFJru3F/aELcnDwHtqDNXxruIZH7bE3vK6xQF4ALCelCZBXFggqPsPXPilVs9L242Iz1ROrbVX0UYXJMMinw==", + "dependencies": { + "abc": "0.5.x", + "fsa": "0.5.x" + }, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/fsa": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/fsa/-/fsa-0.5.1.tgz", + "integrity": "sha512-HMdf0zJNXwP5dxROQb/ncUv+9BxuO4NM5R6/pSbUdfu5CUzMOg7+iP4tQUtBIv18PaScukzfxGIqLyJ3d9wg3Q==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "optional": true + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "optional": true + }, + "node_modules/mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)" + }, + "node_modules/mp3": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/mp3/-/mp3-0.1.0.tgz", + "integrity": "sha512-W9SQWAS8Gn7VvBHBSYnCIz2KAEzZccY+OAKJvO9JRRFBc0MfQ0icb7K4O9Sst/3SW1wcScC+zLNPYoiU6sSXww==", + "peerDependencies": { + "av": "~0.4.0" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/nan": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", + "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==", + "optional": true + }, + "node_modules/pcm-boilerplate": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pcm-boilerplate/-/pcm-boilerplate-0.1.1.tgz", + "integrity": "sha512-2mU5wENQGQoiuYUiRbLJtI8cH7H+1yvjR400XfGH6JONyzERbSbAIFCJnfRUSfbGJi2WJdo1gbTjiTsDyFSY4Q==", + "dependencies": { + "async": "0.2.x", + "chai": "1.7.x", + "underscore": "1.4.x" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pcm-boilerplate/node_modules/async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==" + }, + "node_modules/pcm-boilerplate/node_modules/underscore": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", + "integrity": "sha512-ZqGrAgaqqZM7LGRzNjLnw5elevWb5M8LEoDMadxIW3OWbcv72wMMgKdwOKpd5Fqxe8choLD8HN3iSj3TUh/giQ==" + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "optional": true + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "optional": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true + }, + "node_modules/speaker": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/speaker/-/speaker-0.5.4.tgz", + "integrity": "sha512-0I35CJGgqU1rd/a3qVysR5gLlG+8QlzJcPAEnYvT0BLfuLdJ7JNdlQHwbh7ETNcXDXbzm2O148GEAoAER54Dvw==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.3.0", + "buffer-alloc": "^1.1.0", + "debug": "^4.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "node_modules/underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha512-5WsVTFcH1ut/kkhAaHf4PVgI8c7++GiVcpCGxPouI6ZVjsqPnSDf8h/8HtVqc0t4fzRXwnMK70EcZeAs3PIddg==" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "optional": true + }, + "node_modules/web-audio-api": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/web-audio-api/-/web-audio-api-0.2.2.tgz", + "integrity": "sha512-XidLn3tEz8V9jwuV4OOVTOgNHp3WT6SQwv28Ad3lNXU4R9aPxWDYnocfVBh/OIna96jYPpiuP74KvSrTIF0OTg==", + "dependencies": { + "aac": "0.1.x", + "alac": "0.1.x", + "async": "0.9.x", + "audiobuffer": "0.2.x", + "av": "0.4.x", + "flac": "0.3.x", + "mp3": "0.1.x", + "pcm-boilerplate": "0.1.x", + "underscore": "1.8.x" + }, + "engines": { + "node": ">=0.10" + } + } + }, + "dependencies": { + "aac": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/aac/-/aac-0.1.3.tgz", + "integrity": "sha512-mhkqrzCOMndmoQovW43ry8tkMttuvKcpU0u9/K7zI+lF5NtCY2NE+HwAPiEgd3rHK7IuBT1ZsGL+LKeCPW9btQ==", + "requires": {} + }, + "abc": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/abc/-/abc-0.5.1.tgz", + "integrity": "sha512-WRBP9wjuEdmzw1yFHCVf7Qp/PXSmfuUSX3FSs+5+uLG4qGKmhOPKl8LtZaG0p6xxuB6hX1tIzH4VaHL23+bU5A==" + }, + "alac": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/alac/-/alac-0.1.0.tgz", + "integrity": "sha512-+NBR/Nj/5zndHO7Oz4EOE7Qj+v+hk/0edJerBhjMQRznyjfaYV6/W+tUOOlLTZ0BWWD4p6eb11KKDHoPW5LsCw==", + "requires": {} + }, + "assertion-error": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.0.tgz", + "integrity": "sha512-g/gZV+G476cnmtYI+Ko9d5khxSoCSoom/EaNmmCfwpOvBXEJ18qwFrxfP1/CsIqk2no1sAKKwxndV0tP7ROOFQ==" + }, + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==" + }, + "audiobuffer": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/audiobuffer/-/audiobuffer-0.2.0.tgz", + "integrity": "sha512-wEZ3iAOK1yNCy1PNcSe2V1pzzCV5rezYg0r/TRwojZBIVupQF56ioI0x5PGgatmWxJ4t8sWXymg8AFfopPXfrg==", + "requires": { + "underscore": "1.4.x" + }, + "dependencies": { + "underscore": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", + "integrity": "sha512-ZqGrAgaqqZM7LGRzNjLnw5elevWb5M8LEoDMadxIW3OWbcv72wMMgKdwOKpd5Fqxe8choLD8HN3iSj3TUh/giQ==" + } + } + }, + "av": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/av/-/av-0.4.9.tgz", + "integrity": "sha512-MvkT0k+co6o+zLMrBFFeVhYcG/S/jzy+2p00c/VwA71q6g90J28qUNh93NabKrcN06bkwFK0OeiEpFsQd7TS7g==", + "requires": { + "coffeeify": "^0.6.0", + "speaker": "^0.3.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "optional": true + }, + "speaker": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/speaker/-/speaker-0.3.1.tgz", + "integrity": "sha512-LEqSy+FHYHPZj4kX8NHylzaOmy+VIqj57enm2GS4B568hj0SdKDYa9jALCGQy43LZa/JmQk1iF0nlMVbS1PfPg==", + "optional": true, + "requires": { + "bindings": "^1.2.1", + "debug": "^2.2.0", + "nan": "^2.2.0", + "readable-stream": "^2.0.5" + } + } + } + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==" + }, + "chai": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-1.7.2.tgz", + "integrity": "sha512-iTItmoMR+S+g8g0xU7db2mrr2LeLMJ6Y+YJwJEOUSaVTzm6qyTBfj5r+5x+XQhlXUfVn6WfFS4sXpEtMg6Qwaw==", + "requires": { + "assertion-error": "1.0.0" + } + }, + "coffee-script": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.7.1.tgz", + "integrity": "sha512-W3s+SROY73OmrSGtPTTW/2wp2rmW5vuh0/tUuCK1NvTuyzLOVPccIP9whmhZ4cYWcr2NJPNENZIFaAMkTD5G3w==", + "requires": { + "mkdirp": "~0.3.5" + } + }, + "coffeeify": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/coffeeify/-/coffeeify-0.6.0.tgz", + "integrity": "sha512-nt2rZwyeqLnzdbC15ZUBnQtokHLqNnbgfpUMYzAk1Pa33hObdtXnDV0SmTj2DWbzp47MpR87ix3uKHyutnzjsg==", + "requires": { + "coffee-script": "~1.7.0", + "convert-source-map": "~0.3.3", + "through": "~2.3.4" + } + }, + "convert-source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", + "integrity": "sha512-+4nRk0k3oEpwUB7/CalD7xE2z4VmtEnnq0GO2IPTkrooTrAhEsWvuLF5iWP1dXrwluki/azwXV1ve7gtYuPldg==" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "optional": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "flac": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/flac/-/flac-0.3.0.tgz", + "integrity": "sha512-52oFJru3F/aELcnDwHtqDNXxruIZH7bE3vK6xQF4ALCelCZBXFggqPsPXPilVs9L242Iz1ROrbVX0UYXJMMinw==", + "requires": { + "abc": "0.5.x", + "fsa": "0.5.x" + } + }, + "fsa": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/fsa/-/fsa-0.5.1.tgz", + "integrity": "sha512-HMdf0zJNXwP5dxROQb/ncUv+9BxuO4NM5R6/pSbUdfu5CUzMOg7+iP4tQUtBIv18PaScukzfxGIqLyJ3d9wg3Q==" + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "optional": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "optional": true + }, + "mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==" + }, + "mp3": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/mp3/-/mp3-0.1.0.tgz", + "integrity": "sha512-W9SQWAS8Gn7VvBHBSYnCIz2KAEzZccY+OAKJvO9JRRFBc0MfQ0icb7K4O9Sst/3SW1wcScC+zLNPYoiU6sSXww==", + "requires": {} + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "nan": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", + "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==", + "optional": true + }, + "pcm-boilerplate": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pcm-boilerplate/-/pcm-boilerplate-0.1.1.tgz", + "integrity": "sha512-2mU5wENQGQoiuYUiRbLJtI8cH7H+1yvjR400XfGH6JONyzERbSbAIFCJnfRUSfbGJi2WJdo1gbTjiTsDyFSY4Q==", + "requires": { + "async": "0.2.x", + "chai": "1.7.x", + "underscore": "1.4.x" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==" + }, + "underscore": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", + "integrity": "sha512-ZqGrAgaqqZM7LGRzNjLnw5elevWb5M8LEoDMadxIW3OWbcv72wMMgKdwOKpd5Fqxe8choLD8HN3iSj3TUh/giQ==" + } + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "optional": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true + }, + "speaker": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/speaker/-/speaker-0.5.4.tgz", + "integrity": "sha512-0I35CJGgqU1rd/a3qVysR5gLlG+8QlzJcPAEnYvT0BLfuLdJ7JNdlQHwbh7ETNcXDXbzm2O148GEAoAER54Dvw==", + "requires": { + "bindings": "^1.3.0", + "buffer-alloc": "^1.1.0", + "debug": "^4.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha512-5WsVTFcH1ut/kkhAaHf4PVgI8c7++GiVcpCGxPouI6ZVjsqPnSDf8h/8HtVqc0t4fzRXwnMK70EcZeAs3PIddg==" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "optional": true + }, + "web-audio-api": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/web-audio-api/-/web-audio-api-0.2.2.tgz", + "integrity": "sha512-XidLn3tEz8V9jwuV4OOVTOgNHp3WT6SQwv28Ad3lNXU4R9aPxWDYnocfVBh/OIna96jYPpiuP74KvSrTIF0OTg==", + "requires": { + "aac": "0.1.x", + "alac": "0.1.x", + "async": "0.9.x", + "audiobuffer": "0.2.x", + "av": "0.4.x", + "flac": "0.3.x", + "mp3": "0.1.x", + "pcm-boilerplate": "0.1.x", + "underscore": "1.8.x" + } + } + } +} diff --git a/server/package.json b/server/package.json new file mode 100644 index 000000000..02b30a41a --- /dev/null +++ b/server/package.json @@ -0,0 +1,17 @@ +{ + "name": "@strudel.cycles/server", + "version": "0.0.1", + "description": "Experimental Strudel node server", + "main": "server.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "speaker": "^0.5.4", + "web-audio-api": "^0.2.2" + } +} diff --git a/server/repl.js b/server/repl.js new file mode 100644 index 000000000..17fb759d2 --- /dev/null +++ b/server/repl.js @@ -0,0 +1,76 @@ +import repl from 'repl'; +import { evalScope, evaluate } from '@strudel.cycles/eval'; +import { AudioContext } from 'web-audio-api'; +import Speaker from 'speaker'; +import controls from '@strudel.cycles/core/controls.mjs'; +import { prepareSamples, playBuffer } from './sampler.js'; +import { randomHeadline } from './headline.js'; + +/* + This is just a POC of how a strudel cli / repl could look like +*/ + +// setup audio +const context = new AudioContext(); +context.outStream = new Speaker({ + channels: context.format.numberOfChannels, + bitDepth: context.format.bitDepth, + sampleRate: context.sampleRate, +}); +console.log('now loading samples..'); +const buffers = await prepareSamples(context, './samples/'); +console.log(''); + +// scheduler +let tick = 0; +const slice = 0.5; +const latency = 1; +/* console.log('latency', latency); +console.log('querying every', slice, 's'); */ +const offset = context.currentTime + latency; +let pattern; +setInterval(() => { + if (pattern) { + try { + pattern + .queryArc(tick * slice, ++tick * slice) + .filter((hap) => hap.hasOnset()) + .forEach((hap) => { + const t = hap.whole.begin.valueOf() + offset; + const { s, n } = hap.value; + const bank = buffers[s]; + if (bank?.length) { + const index = (n ?? 0) % bank.length; + playBuffer(context, bank[index], t); + } + }); + } catch (err) { + console.error('query error', err); + } + } +}, slice * 1000); + +await evalScope(controls, import('@strudel.cycles/core'), import('@strudel.cycles/mini')); +console.log(`${randomHeadline()} + +welcome to the experimental strudel cli <3 + +available samples: ${Object.entries(buffers) + .map(([key, samples]) => `${key} (${samples.length})`) + .join(', ')} +you can add samples to the samples folder (.wav, .ogg, .mp3) + +please enter a pattern, e.g. s("bd(3,8),~ sd,hh(3,8,1)") +`); +// repl +repl.start({ + prompt: '>>>', + eval: async function myEval(cmd, context, filename, callback) { + try { + pattern = (await evaluate(cmd)).pattern; + } catch (err) { + console.error('query error', err.message); + } + callback(null); + }, +}); diff --git a/server/sampler.js b/server/sampler.js new file mode 100644 index 000000000..5413fa28f --- /dev/null +++ b/server/sampler.js @@ -0,0 +1,41 @@ +import fs from 'fs'; + +export const loadSample = (context, path) => { + console.log(`load sample: ${path}`); + return new Promise((resolve, reject) => { + fs.readFile(new URL(path, import.meta.url), function (err, buffer) { + if (err) reject(err); + context.decodeAudioData(buffer, resolve); + }); + }); +}; + +export async function prepareSamples(context, path, ignore = ['.DS_Store', 'Thumbs.db']) { + const ignored = (filename) => !ignore.includes(filename); + const folders = fs.readdirSync(path).filter(ignored); + return Object.fromEntries( + await Promise.all( + folders.map(async (folder) => { + return [ + folder, + await Promise.all( + fs + .readdirSync(path + folder) + .filter(ignored) + .map((filename) => path + folder + '/' + filename) + .map((filepath) => loadSample(context, filepath)), + ), + ]; + }, []), + ), + ); +} + +export const playBuffer = (context, audioBuffer, start = 0) => { + const bufferNode = context.createBufferSource(); + bufferNode.connect(context.destination); + bufferNode.buffer = audioBuffer; + bufferNode.loop = false; + bufferNode.start(start); + bufferNode.stop(start + audioBuffer.length / audioBuffer.sampleRate); +}; diff --git a/server/samples/bd/president_bd.mp3 b/server/samples/bd/president_bd.mp3 new file mode 100644 index 000000000..d83d5dc09 Binary files /dev/null and b/server/samples/bd/president_bd.mp3 differ diff --git a/server/samples/hh/president_hh.mp3 b/server/samples/hh/president_hh.mp3 new file mode 100644 index 000000000..9ce7d3966 Binary files /dev/null and b/server/samples/hh/president_hh.mp3 differ diff --git a/server/samples/oh/president_oh.mp3 b/server/samples/oh/president_oh.mp3 new file mode 100644 index 000000000..9e03bf49d Binary files /dev/null and b/server/samples/oh/president_oh.mp3 differ diff --git a/server/samples/sd/president_sd.mp3 b/server/samples/sd/president_sd.mp3 new file mode 100644 index 000000000..2af81031d Binary files /dev/null and b/server/samples/sd/president_sd.mp3 differ diff --git a/server/samples/sd/president_sd2.mp3 b/server/samples/sd/president_sd2.mp3 new file mode 100644 index 000000000..ac244a41d Binary files /dev/null and b/server/samples/sd/president_sd2.mp3 differ diff --git a/server/samples/snap/president_snap.mp3 b/server/samples/snap/president_snap.mp3 new file mode 100644 index 000000000..938ff333a Binary files /dev/null and b/server/samples/snap/president_snap.mp3 differ