diff --git a/CHANGELOG.md b/CHANGELOG.md index 0225e10a..1680f1a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Change log +## 3.0.0-beta + * Feature: Core language switched to from [scale-workshop-core](https://github.com/xenharmonic-devs/scale-workshop-core) to [sonic-weave](https://github.com/xenharmonic-devs/sonic-weave) + * Feature: Virtual piano now supports up to 4 layers of colors + * Feature: Character palette with tooltips for syntax beyond ASCII [#533](https://github.com/xenharmonic-devs/scale-workshop/issues/533) + * Feature: Interval matrix simplified by default [#536](https://github.com/xenharmonic-devs/scale-workshop/issues/536) + * Feature: Convert scale to enumeration [#538](https://github.com/xenharmonic-devs/scale-workshop/issues/538) + * Feature: More MOS coloring options [#554](https://github.com/xenharmonic-devs/scale-workshop/issues/554) + * Feature: Variety and brightness signatures show in the interval matrix [#568](https://github.com/xenharmonic-devs/scale-workshop/issues/568) + * Feature: Periodic equally tempered grids supported on the lattice tab + * Feature: Lattice label sizes customizable [#581](https://github.com/xenharmonic-devs/scale-workshop/issues/581) + * Feature: Lattice colors inverted and scale colors incorporated [#586](https://github.com/xenharmonic-devs/scale-workshop/issues/586) + * Feature: Scott Dakota's prime rings on the lattice tab [#551](https://github.com/xenharmonic-devs/scale-workshop/issues/551) + * Feature: Tonnetz prime ellipse coordinates on the lattice tab [#588](https://github.com/xenharmonic-devs/scale-workshop/issues/588) + * Feature: New `latticeView()` command for displaying the order of intervals (prior to sorting) [#597](https://github.com/xenharmonic-devs/scale-workshop/issues/597) + * Alpha cycle issues: [#574](https://github.com/xenharmonic-devs/scale-workshop/issues/574), [#579](https://github.com/xenharmonic-devs/scale-workshop/issues/579) + ## 2.4.1 * Bug fix: Unison is no longer affected by random variance [#613](https://github.com/xenharmonic-devs/scale-workshop/issues/613) diff --git a/LICENSE b/LICENSE index 62ccc0e4..e36d9b60 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Xenharmonic Developers +Copyright (c) 2022-2024 Xenharmonic Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 9850164e..12880aab 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,11 @@ ![Scale Workshop screenshot](https://raw.githubusercontent.com/xenharmonic-devs/scale-workshop/main/src/assets/img/opengraph-image.png) +## Beta Warning! +This release is in beta. Not everything has been implemented and documentation has not been synchronized with the new features. + +Some of the new features are documented over at [sonic-weave](https://github.com/xenharmonic-devs/sonic-weave). + ## Description [Scale Workshop](https://scaleworkshop.plainsound.org/) allows you to design microtonal scales and play them in your web browser. Export your scales for use with VST instruments. Convert Scala files to various tuning formats. diff --git a/cypress/e2e/basic.cy.ts b/cypress/e2e/basic.cy.ts index a0736e16..df334961 100644 --- a/cypress/e2e/basic.cy.ts +++ b/cypress/e2e/basic.cy.ts @@ -8,14 +8,16 @@ describe("Basic test", () => { it("preserves the base frequency when changing tabs", () => { cy.visit("/"); - cy.get(".real-valued").clear() - cy.get(".real-valued").type("432") - cy.get(".real-valued").trigger("change") - cy.get(".real-valued").should("have.value", "432"); + cy.get("#auto-frequency").click() + cy.get("#base-frequency").clear() + cy.get("#base-frequency").type("432") + cy.get("#base-frequency").trigger("change") + cy.get("#base-frequency").should("have.value", "432"); // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(400); // Wait for debounce to expire. cy.get("a").contains("Synth").click(); - cy.url().should("contain", "f="); + cy.get("a").contains("Build Scale").click(); + cy.get("#base-frequency").should("have.value", "432"); }); }); diff --git a/cypress/e2e/compatibility.cy.ts b/cypress/e2e/compatibility.cy.ts new file mode 100644 index 00000000..d2bb8ff5 --- /dev/null +++ b/cypress/e2e/compatibility.cy.ts @@ -0,0 +1,17 @@ +// https://on.cypress.io/api + +describe("Scale Workshop 2 compatibility", () => { + it("ignores invalid scale lines", () => { + cy.visit("/?l=1_7nF74_5F4_gtFe8_bF8_2c1F1kw_pFg_1jFw_3dF1s_2F1&version=2.4.0"); + cy.contains("h2", "Scale data"); + cy.get("#scale-data").should('have.value', '// 1\n275/256 black\n5/4 white\n605/512 white\n11/8 black\n3025/2048 white\n25/16 black\n55/32 white\n121/64 white\n2/1 black'); + }); +}); + +describe("Scale Workshop 1 compatibility", () => { + it("supports all line types", () => { + cy.visit("?name=Test%20scale&data=1%2C23%0A1%5C3%0A3%2F2%0A1001.2%0A2%2F1&freq=420&midi=42&vert=5&horiz=1&colors=white%20black%20white%20black%20white&waveform=triangle&env=perc-medium"); + cy.contains("h2", "Scale data"); + cy.get("#scale-data").should('have.value', '1.23e black\n1\\3 white\n3/2 black\n1001.2 white\n2/1 white'); + }); +}); diff --git a/index.html b/index.html index a21980a9..f57c7db4 100644 --- a/index.html +++ b/index.html @@ -4,11 +4,11 @@ - Scale Workshop + Scale Workshop 3 - + - + diff --git a/package-lock.json b/package-lock.json index 78111f99..ed881e13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,21 @@ { "name": "scale-workshop", - "version": "2.4.1", + "version": "3.0.0-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "scale-workshop", - "version": "2.4.1", + "version": "3.0.0-beta.1", "dependencies": { "isomorphic-qwerty": "^0.0.2", + "ji-lattice": "^0.0.2", "jszip": "^3.10.1", - "moment-of-symmetry": "^0.4.1", + "moment-of-symmetry": "^0.4.2", "pinia": "^2.1.7", - "qs": "^6.11.2", - "scale-workshop-core": "github:xenharmonic-devs/scale-workshop-core#v0.1.5", + "qs": "^6.12.0", + "sonic-weave": "github:xenharmonic-devs/sonic-weave#v0.0.4", + "sw-synth": "^0.1.0", "temperaments": "^0.5.3", "vue": "^3.3.4", "vue-router": "^4.3.0", @@ -22,26 +24,26 @@ "xen-midi": "^0.1.2" }, "devDependencies": { - "@rushstack/eslint-patch": "^1.7.2", - "@tsconfig/node18": "^18.2.2", + "@rushstack/eslint-patch": "^1.8.0", + "@tsconfig/node18": "^18.2.3", "@types/jsdom": "^21.1.6", - "@types/node": "^18.19.21", - "@types/qs": "^6.9.12", + "@types/node": "^18.19.26", + "@types/qs": "^6.9.14", "@vitejs/plugin-vue": "^4.6.2", "@vue/eslint-config-prettier": "^8.0.0", "@vue/eslint-config-typescript": "^12.0.0", - "@vue/test-utils": "^2.4.4", + "@vue/test-utils": "^2.4.5", "@vue/tsconfig": "^0.4.0", - "cypress": "^13.6.6", + "cypress": "^13.7.1", "eslint": "^8.57.0", "eslint-plugin-cypress": "^2.15.1", - "eslint-plugin-vue": "^9.22.0", + "eslint-plugin-vue": "^9.23.0", "jsdom": "^22.1.0", "npm-run-all2": "^6.1.2", "prettier": "^3.2.5", "start-server-and-test": "^2.0.3", "typescript": "~5.2.0", - "vite": "^4.5.2", + "vite": "^4.5.3", "vitest": "^0.34.6", "vue-tsc": "^1.8.27" } @@ -150,246 +152,6 @@ "ms": "^2.1.1" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/linux-x64": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", @@ -406,102 +168,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -798,9 +464,9 @@ } }, "node_modules/@rushstack/eslint-patch": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.7.2.tgz", - "integrity": "sha512-RbhOOTCNoCrbfkRyoXODZp75MlpiHMgbE5MEBZAnnnLyQNgrigEj4p0lzsMDyc1zVsJDLrivB58tgg3emX0eEA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.8.0.tgz", + "integrity": "sha512-0HejFckBN2W+ucM6cUOlwsByTKt9/+0tWhqUffNIcHqCXkthY/mZ7AuYPK/2IIaGWhdl0h+tICDO0ssLMd6XMQ==", "dev": true }, "node_modules/@sideway/address": { @@ -840,9 +506,9 @@ } }, "node_modules/@tsconfig/node18": { - "version": "18.2.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.2.tgz", - "integrity": "sha512-d6McJeGsuoRlwWZmVIeE8CUA27lu6jLjvv1JzqmpsytOYYbVi1tHZEnwCNVOXnj4pyLvneZlFlpXUK+X9wBWyw==", + "version": "18.2.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.3.tgz", + "integrity": "sha512-5GKTU9bfn4L37G9IdK8wcHfvyMijzw1uKNCd2Rs75V7fZK/l2OjGJ8Aa2myqNnESjekm/udpCnFH9qR9yPCtmw==", "dev": true }, "node_modules/@types/chai": { @@ -878,18 +544,18 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.19.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.21.tgz", - "integrity": "sha512-2Q2NeB6BmiTFQi4DHBzncSoq/cJMLDdhPaAoJFnFCyD9a8VPZRf7a1GAwp1Edb7ROaZc5Jz/tnZyL6EsWMRaqw==", + "version": "18.19.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.26.tgz", + "integrity": "sha512-+wiMJsIwLOYCvUqSdKTrfkS8mpTp+MPINe6+Np4TAGFWWRWiBQ5kSq9nZGCSPkzx9mvT+uEukzpX4MOSCydcvw==", "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/qs": { - "version": "6.9.12", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.12.tgz", - "integrity": "sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg==", + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz", + "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", "dev": true }, "node_modules/@types/semver": { @@ -1423,22 +1089,13 @@ "integrity": "sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==" }, "node_modules/@vue/test-utils": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.4.tgz", - "integrity": "sha512-8jkRxz8pNhClAf4Co4ZrpAoFISdvT3nuSkUlY6Ys6rmTpw3DMWG/X3mw3gQ7QJzgCZO9f+zuE2kW57fi09MW7Q==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.5.tgz", + "integrity": "sha512-oo2u7vktOyKUked36R93NB7mg2B+N7Plr8lxp2JBGwr18ch6EggFjixSCdIVVLkT6Qr0z359Xvnafc9dcKyDUg==", "dev": true, "dependencies": { "js-beautify": "^1.14.9", - "vue-component-type-helpers": "^1.8.21" - }, - "peerDependencies": { - "@vue/server-renderer": "^3.0.1", - "vue": "^3.0.1" - }, - "peerDependenciesMeta": { - "@vue/server-renderer": { - "optional": true - } + "vue-component-type-helpers": "^2.0.0" } }, "node_modules/@vue/tsconfig": { @@ -1594,6 +1251,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/aperiodic-oscillator": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/aperiodic-oscillator/-/aperiodic-oscillator-0.1.0.tgz", + "integrity": "sha512-i85h6R8nI03sRkNOIDcc/f1c1V5r+UcSYy3/stxhVUnBuwLAtCkA3FB9ZoIu8Z5rMkaNoEZuTCDvN2t+1ijYhw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/frostburn" + } + }, "node_modules/arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", @@ -2173,9 +1839,9 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/cypress": { - "version": "13.6.6", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.6.6.tgz", - "integrity": "sha512-S+2S9S94611hXimH9a3EAYt81QM913ZVA03pUmGDfLTFa5gyp85NJ8dJGSlEAEmyRsYkioS1TtnWtbv/Fzt11A==", + "version": "13.7.1", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.7.1.tgz", + "integrity": "sha512-4u/rpFNxOFCoFX/Z5h+uwlkBO4mWzAjveURi3vqdSu56HPvVdyGTxGw4XKGWt399Y1JwIn9E1L9uMXQpc0o55w==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -2672,12 +2338,13 @@ } }, "node_modules/eslint-plugin-vue": { - "version": "9.22.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.22.0.tgz", - "integrity": "sha512-7wCXv5zuVnBtZE/74z4yZ0CM8AjH6bk4MQGm7hZjUC2DBppKU5ioeOk5LGSg/s9a1ZJnIsdPLJpXnu1Rc+cVHg==", + "version": "9.24.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.24.0.tgz", + "integrity": "sha512-9SkJMvF8NGMT9aQCwFc5rj8Wo1XWSMSHk36i7ZwdI614BU7sIOR28ZjuFPKp8YGymZN12BSEbiSwa7qikp+PBw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", + "globals": "^13.24.0", "natural-compare": "^1.4.0", "nth-check": "^2.1.1", "postcss-selector-parser": "^6.0.15", @@ -3748,6 +3415,18 @@ "node": ">=10.0.0" } }, + "node_modules/ji-lattice": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ji-lattice/-/ji-lattice-0.0.2.tgz", + "integrity": "sha512-nLCvHXi0zIhtYVBHaipnsFdMyZG6//xsTcnHidXtv3+r/q2IyesSQ9OSHS+F2cB7lGmaceiEEcplXTnMGY/j6w==", + "dependencies": { + "xen-dev-utils": "^0.2.7" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/frostburn" + } + }, "node_modules/joi": { "version": "17.12.2", "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.2.tgz", @@ -4321,11 +4000,11 @@ } }, "node_modules/moment-of-symmetry": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/moment-of-symmetry/-/moment-of-symmetry-0.4.1.tgz", - "integrity": "sha512-uT4K/nUca6e8z/LruWbZROqi0efB+P3zZ5U4ffGWigKqkvGkUGI12pGWbssLjMobzoJHaluFgnxmD2N3fb6uGA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/moment-of-symmetry/-/moment-of-symmetry-0.4.2.tgz", + "integrity": "sha512-XBzU01kDgQfN0JacGSwMOxJOk5EhwcaojbDQDDdZF/k16ze/VP9X8Cz1Gy8Hmhg+WMu0axfTVP4ufzhoFt0C4g==", "dependencies": { - "xen-dev-utils": "^0.2.7" + "xen-dev-utils": "^0.2.8" }, "funding": { "type": "github", @@ -4961,11 +4640,11 @@ } }, "node_modules/qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.0.tgz", + "integrity": "sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -5245,18 +4924,6 @@ "node": ">=v12.22.7" } }, - "node_modules/scale-workshop-core": { - "version": "0.1.5", - "resolved": "git+ssh://git@github.com/xenharmonic-devs/scale-workshop-core.git#77422327f9258e22635a3857994c373ee1e80eff", - "license": "MIT", - "dependencies": { - "xen-dev-utils": "0.2.8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/frostburn" - } - }, "node_modules/seedrandom": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", @@ -5392,6 +5059,25 @@ "node": ">=8" } }, + "node_modules/sonic-weave": { + "version": "0.0.4", + "resolved": "git+ssh://git@github.com/xenharmonic-devs/sonic-weave.git#9643f6c7958143289ad05f016287ff4ed8025ccf", + "license": "MIT", + "dependencies": { + "moment-of-symmetry": "^0.4.2", + "xen-dev-utils": "^0.2.8" + }, + "bin": { + "sonic-weave": "bin/sonic-weave.js" + }, + "engines": { + "node": ">=10.6.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/frostburn" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -5641,6 +5327,18 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/sw-synth": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/sw-synth/-/sw-synth-0.1.0.tgz", + "integrity": "sha512-JUUdHz5jNLlr3Q+crEY6kM6cS4Dx0KGHV7eiCU3qTJLTCKI9XUc4T1SL4kJblcf4f2cxcN/f6k0rCXX1kzfIcA==", + "dependencies": { + "aperiodic-oscillator": "^0.1.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/frostburn" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -5988,9 +5686,9 @@ "dev": true }, "node_modules/vite": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", - "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", + "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", "dev": true, "dependencies": { "esbuild": "^0.18.10", @@ -6163,9 +5861,9 @@ } }, "node_modules/vue-component-type-helpers": { - "version": "1.8.27", - "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-1.8.27.tgz", - "integrity": "sha512-0vOfAtI67UjeO1G6UiX5Kd76CqaQ67wrRZiOe7UAb9Jm6GzlUr/fC7CV90XfwapJRjpCMaZFhv1V0ajWRmE9Dg==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.0.7.tgz", + "integrity": "sha512-7e12Evdll7JcTIocojgnCgwocX4WzIYStGClBQ+QuWPinZo/vQolv2EMq4a3lg16TKfwWafLimG77bxb56UauA==", "dev": true }, "node_modules/vue-eslint-parser": { diff --git a/package.json b/package.json index 4c3d9f98..48d7c4cb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scale-workshop", - "version": "2.4.1", + "version": "3.0.0-beta.1", "scripts": { "dev": "vite", "build": "run-p type-check \"build-only {@}\" --", @@ -16,11 +16,13 @@ }, "dependencies": { "isomorphic-qwerty": "^0.0.2", + "ji-lattice": "^0.0.2", "jszip": "^3.10.1", - "moment-of-symmetry": "^0.4.1", + "moment-of-symmetry": "^0.4.2", "pinia": "^2.1.7", - "qs": "^6.11.2", - "scale-workshop-core": "github:xenharmonic-devs/scale-workshop-core#v0.1.5", + "qs": "^6.12.0", + "sonic-weave": "github:xenharmonic-devs/sonic-weave#v0.0.4", + "sw-synth": "^0.1.0", "temperaments": "^0.5.3", "vue": "^3.3.4", "vue-router": "^4.3.0", @@ -29,26 +31,26 @@ "xen-midi": "^0.1.2" }, "devDependencies": { - "@rushstack/eslint-patch": "^1.7.2", - "@tsconfig/node18": "^18.2.2", + "@rushstack/eslint-patch": "^1.8.0", + "@tsconfig/node18": "^18.2.3", "@types/jsdom": "^21.1.6", - "@types/node": "^18.19.21", - "@types/qs": "^6.9.12", + "@types/node": "^18.19.26", + "@types/qs": "^6.9.14", "@vitejs/plugin-vue": "^4.6.2", "@vue/eslint-config-prettier": "^8.0.0", "@vue/eslint-config-typescript": "^12.0.0", - "@vue/test-utils": "^2.4.4", + "@vue/test-utils": "^2.4.5", "@vue/tsconfig": "^0.4.0", - "cypress": "^13.6.6", + "cypress": "^13.7.1", "eslint": "^8.57.0", "eslint-plugin-cypress": "^2.15.1", - "eslint-plugin-vue": "^9.22.0", + "eslint-plugin-vue": "^9.23.0", "jsdom": "^22.1.0", "npm-run-all2": "^6.1.2", "prettier": "^3.2.5", "start-server-and-test": "^2.0.3", "typescript": "~5.2.0", - "vite": "^4.5.2", + "vite": "^4.5.3", "vitest": "^0.34.6", "vue-tsc": "^1.8.27" } diff --git a/public/favicon.png b/public/favicon.png index b3998690..f1e427b8 100644 Binary files a/public/favicon.png and b/public/favicon.png differ diff --git a/src/App.vue b/src/App.vue index 05b46926..cc06afd0 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,22 +1,26 @@ + + diff --git a/src/components/ExporterButtons.vue b/src/components/ExporterButtons.vue new file mode 100644 index 00000000..58868255 --- /dev/null +++ b/src/components/ExporterButtons.vue @@ -0,0 +1,203 @@ + + + + diff --git a/src/components/GridLattice.vue b/src/components/GridLattice.vue new file mode 100644 index 00000000..30ec36e9 --- /dev/null +++ b/src/components/GridLattice.vue @@ -0,0 +1,155 @@ + + + + + diff --git a/src/components/JustIntonationLattice.vue b/src/components/JustIntonationLattice.vue new file mode 100644 index 00000000..ea24e7d9 --- /dev/null +++ b/src/components/JustIntonationLattice.vue @@ -0,0 +1,201 @@ + + + diff --git a/src/components/ModalDialog.vue b/src/components/ModalDialog.vue index 8a44c14f..bf95d913 100644 --- a/src/components/ModalDialog.vue +++ b/src/components/ModalDialog.vue @@ -9,6 +9,10 @@ const props = defineProps({ extraStyle: { default: '', type: String + }, + right: { + default: false, + type: Boolean } }) @@ -73,7 +77,7 @@ watch( + diff --git a/src/components/modals/generation/EulerGenus.vue b/src/components/modals/generation/EulerGenus.vue index 2a33a0f8..1a753fb7 100644 --- a/src/components/modals/generation/EulerGenus.vue +++ b/src/components/modals/generation/EulerGenus.vue @@ -1,23 +1,36 @@ @@ -39,11 +52,29 @@ function generate() { v-model="modal.guideTone" /> +
+ + +
+ diff --git a/src/components/modals/generation/GeneratorSequence.vue b/src/components/modals/generation/GeneratorSequence.vue new file mode 100644 index 00000000..8b800799 --- /dev/null +++ b/src/components/modals/generation/GeneratorSequence.vue @@ -0,0 +1,195 @@ + + + diff --git a/src/components/modals/generation/HarmonicSeries.vue b/src/components/modals/generation/HarmonicSeries.vue index ec4c191d..7ba6da1d 100644 --- a/src/components/modals/generation/HarmonicSeries.vue +++ b/src/components/modals/generation/HarmonicSeries.vue @@ -1,28 +1,26 @@ @@ -55,5 +53,12 @@ function generate() { + diff --git a/src/components/modals/generation/HistoricalScale.vue b/src/components/modals/generation/HistoricalScale.vue index 5b320b23..7f9b2a3c 100644 --- a/src/components/modals/generation/HistoricalScale.vue +++ b/src/components/modals/generation/HistoricalScale.vue @@ -1,33 +1,31 @@ + diff --git a/src/views/AnalysisView.vue b/src/views/AnalysisView.vue index c6a7b541..80e5c3c4 100644 --- a/src/views/AnalysisView.vue +++ b/src/views/AnalysisView.vue @@ -1,21 +1,38 @@ @@ -236,9 +361,29 @@ main { border-collapse: collapse; text-align: center; } +.variety { + border-top: 2px solid; +} +.brightness { + border-left: 2px solid !important; +} +.violator { + color: red; +} +.highlight { + text-decoration: underline; +} +.violator.highlight { + background-color: rgba(255, 255, 100, 0.8); +} +.held { + background-color: var(--color-accent); + color: var(--color-accent-text); +} /* Content layout (medium) */ -div.columns-container { +div.columns-container, +div.bicolumns-container { column-count: 2; column-gap: 1rem; overflow: hidden; @@ -263,4 +408,9 @@ div.column { max-width: 100%; height: auto; } + +/* Equally tempered chord */ +.chord-data { + font-size: 1.2em; +} diff --git a/src/views/LatticeView.vue b/src/views/LatticeView.vue index d15c470c..f3dba428 100644 --- a/src/views/LatticeView.vue +++ b/src/views/LatticeView.vue @@ -1,35 +1,363 @@ - diff --git a/src/views/MidiView.vue b/src/views/MidiView.vue index 593a1578..9e15dabe 100644 --- a/src/views/MidiView.vue +++ b/src/views/MidiView.vue @@ -2,14 +2,14 @@ import { onMounted, onUnmounted, reactive, ref } from 'vue' import { Input, Output, WebMidi, type NoteMessageEvent, type MessageEvent } from 'webmidi' import MidiPiano from '@/components/MidiPiano.vue' -import { useStateStore } from '@/stores/state' import { useMidiStore } from '@/stores/midi' +import { useScaleStore } from '@/stores/scale' const props = defineProps<{ midiInputChannels: Set }>() -const state = useStateStore() +const scale = useScaleStore() const midi = useMidiStore() const inputs = reactive([]) @@ -204,10 +204,10 @@ onUnmounted(() => {
diff --git a/src/views/NotFoundView.vue b/src/views/NotFoundView.vue index 1a784be3..e58ea5a3 100644 --- a/src/views/NotFoundView.vue +++ b/src/views/NotFoundView.vue @@ -4,58 +4,20 @@ */ import OctaplexPortal from '@/components/modals/generation/SummonOctaplex.vue' -import { encodeQuery } from '@/url-encode' -import type { Scale } from 'scale-workshop-core' -import { nextTick, ref } from 'vue' -import { useRouter, type LocationQuery } from 'vue-router' -import { version } from '../../package.json' -import { useAudioStore } from '@/stores/audio' -import { useStateStore } from '@/stores/state' +import { useRouter } from 'vue-router' +import { useScaleStore } from '@/stores/scale' +import { ref } from 'vue' const ritualInProgress = ref(false) const router = useRouter() +const scale = useScaleStore() -const state = useStateStore() - -const audio = useAudioStore() - -function openTheGates(scale: Scale) { - state.scale = scale - - // Unfortunately we need to encode the state here. - // Simply navigating to "/" triggers decoding of the default empty state. - nextTick(() => { - const encodedState = { - scaleName: state.scaleName, - scaleLines: state.scaleLines, - baseFrequency: state.scale.baseFrequency, - baseMidiNote: state.baseMidiNote, - keyColors: state.keyColors, - isomorphicHorizontal: state.isomorphicHorizontal, - isomorphicVertical: state.isomorphicVertical, - keyboardMode: state.keyboardMode, - pianoMode: state.pianoMode, - equaveShift: state.equaveShift, - degreeShift: state.degreeShift, - - waveform: audio.waveform, - attackTime: audio.attackTime, - decayTime: audio.decayTime, - sustainLevel: audio.sustainLevel, - releaseTime: audio.releaseTime, - - pingPongDelayTime: audio.pingPongDelayTime, - pingPongFeedback: audio.pingPongFeedback, - pingPongSeparation: audio.pingPongSeparation, - pingPongGain: audio.pingPongGain - } - - const query = encodeQuery(encodedState) as LocationQuery - query.version = version - - router.push({ path: '/', query }) - }) +function openTheGates(source: string) { + scale.sourceText = source + scale.computeScale() + ritualInProgress.value = false + router.push({ path: '/' }) } @@ -71,8 +33,8 @@ function openTheGates(scale: Scale) { diff --git a/src/views/PreferencesView.vue b/src/views/PreferencesView.vue index d8f2ec0f..4210dcf2 100644 --- a/src/views/PreferencesView.vue +++ b/src/views/PreferencesView.vue @@ -2,8 +2,10 @@ import { UNIX_NEWLINE, WINDOWS_NEWLINE } from '@/constants' import { useStateStore } from '@/stores/state' +import { useScaleStore } from '@/stores/scale' const state = useStateStore() +const scale = useScaleStore()