diff --git a/src/stores/scale.ts b/src/stores/scale.ts index 2567a5a3..7e6386b3 100644 --- a/src/stores/scale.ts +++ b/src/stores/scale.ts @@ -1,5 +1,5 @@ import { Scale } from '@/scale' -import { midiNoteNumberToEnharmonics, type AccidentalStyle } from '@/utils' +import { midiNoteNumberToEnharmonics, type AccidentalStyle, syncValues } from '@/utils' import { defineStore } from 'pinia' import { computed, ref, watch } from 'vue' import { mmod, mtof } from 'xen-dev-utils' @@ -272,9 +272,7 @@ export const useScaleStore = defineStore('scale', () => { }) // Local storage watchers - watch(accidentalPreference, (newValue) => localStorage.setItem('accidentalPreference', newValue)) - watch(hasLeftOfZ, (newValue) => window.localStorage.setItem('hasLeftOfZ', newValue.toString())) - watch(gas, (newValue) => window.localStorage.setItem('gas', newValue.toString())) + syncValues({ accidentalPreference, hasLeftOfZ, gas }) function latticeView(this: ExpressionVisitor) { const scale = this.getCurrentScale() diff --git a/src/stores/state.ts b/src/stores/state.ts index 11e99800..c56231ea 100644 --- a/src/stores/state.ts +++ b/src/stores/state.ts @@ -1,6 +1,7 @@ import { reactive, ref, watch } from 'vue' import { defineStore } from 'pinia' import { UNIX_NEWLINE } from '@/constants' +import { syncValues } from '@/utils' export const useStateStore = defineStore('state', () => { const isomorphicVertical = ref(5) @@ -23,7 +24,15 @@ export const useStateStore = defineStore('state', () => { const centsFractionDigits = ref(parseInt(storage.getItem('centsFractionDigits') ?? '3', 10)) const decimalFractionDigits = ref(parseInt(storage.getItem('decimalFractionDigits') ?? '5', 10)) const showVirtualQwerty = ref(storage.getItem('showVirtualQwerty') === 'true') + + // Analysis preferences const intervalMatrixIndexing = ref(parseInt(storage.getItem('intervalMatrixIndexing') ?? '0', 10)) + const maxMatrixWidth = ref(parseInt(storage.getItem('maxMatrixWidth') ?? '100', 10)) + const calculateConstantStructureViolations = ref( + storage.getItem('calculateConstantStructureViolations') === 'true' + ) + const calculateVariety = ref(storage.getItem('calculateVariety') === 'true') + const calculateBrightness = ref(storage.getItem('calculateBrightness') === 'true') // Special keyboard codes also from local storage. const deactivationCode = ref(storage.getItem('deactivationCode') ?? 'Backquote') @@ -33,33 +42,30 @@ export const useStateStore = defineStore('state', () => { const degreeDownCode = ref(storage.getItem('degreeDownCode') ?? 'NumpadSubtract') // Local storage watchers - watch(newline, (newValue) => window.localStorage.setItem('newline', newValue)) + syncValues({ + newline, + centsFractionDigits, + decimalFractionDigits, + showVirtualQwerty, + intervalMatrixIndexing, + maxMatrixWidth, + calculateConstantStructureViolations, + calculateVariety, + calculateBrightness, + deactivationCode, + equaveUpCode, + equaveDownCode, + degreeUpCode, + degreeDownCode + }) watch( colorScheme, (newValue) => { - window.localStorage.setItem('colorScheme', newValue) + storage.setItem('colorScheme', newValue) document.documentElement.setAttribute('data-theme', newValue) }, { immediate: true } ) - watch(centsFractionDigits, (newValue) => - window.localStorage.setItem('centsFractionDigits', newValue.toString()) - ) - watch(decimalFractionDigits, (newValue) => - window.localStorage.setItem('decimalFractionDigits', newValue.toString()) - ) - watch(showVirtualQwerty, (newValue) => - window.localStorage.setItem('showVirtualQwerty', newValue.toString()) - ) - watch(intervalMatrixIndexing, (newValue) => - window.localStorage.setItem('intervalMatrixIndexing', newValue.toString()) - ) - // Store keymaps - watch(deactivationCode, (newValue) => window.localStorage.setItem('deactivationCode', newValue)) - watch(equaveUpCode, (newValue) => window.localStorage.setItem('equaveUpCode', newValue)) - watch(equaveDownCode, (newValue) => window.localStorage.setItem('equaveDownCode', newValue)) - watch(degreeUpCode, (newValue) => window.localStorage.setItem('degreeUpCode', newValue)) - watch(degreeDownCode, (newValue) => window.localStorage.setItem('degreeDownCode', newValue)) return { // Live state @@ -75,6 +81,10 @@ export const useStateStore = defineStore('state', () => { decimalFractionDigits, showVirtualQwerty, intervalMatrixIndexing, + maxMatrixWidth, + calculateConstantStructureViolations, + calculateVariety, + calculateBrightness, deactivationCode, equaveUpCode, equaveDownCode, diff --git a/src/utils.ts b/src/utils.ts index 57a9e18e..6f9db033 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,4 @@ -import { computed, type ComputedRef } from 'vue' +import { computed, watch, type ComputedRef, type Ref } from 'vue' import { gcd, mmod } from 'xen-dev-utils' import { evaluateExpression, @@ -445,3 +445,13 @@ export function annotateColors(sourceLines: string[], keyColors: string[]) { sourceLines[i] += ' ' + keyColors[mmod(i + 1, keyColors.length)].replace(/%/g, '') } } + +/** + * Synchronize local storage with the values of Vue refs. + * @param values Vue refs to watch in a `{ref1, ref2}` record. + */ +export function syncValues(values: Record) { + for (const [key, value] of Object.entries(values)) { + watch(value, (newValue) => window.localStorage.setItem(key, String(newValue))) + } +} diff --git a/src/views/AnalysisView.vue b/src/views/AnalysisView.vue index 80e5c3c4..20d84c61 100644 --- a/src/views/AnalysisView.vue +++ b/src/views/AnalysisView.vue @@ -17,13 +17,12 @@ import { useScaleStore } from '@/stores/scale' import { mmod } from 'xen-dev-utils' import { OCTAVE } from '@/constants' -const MAX_SCALE_SIZE = 100 - const audio = useAudioStore() const state = useStateStore() const scale = useScaleStore() const cellFormat = ref<'best' | 'cents' | 'decimal'>('best') +const showOptions = ref(false) const trailLongevity = ref(70) const maxOtonalRoot = ref(16) const maxUtonalRoot = ref(23) @@ -80,7 +79,9 @@ function formatMatrixCell(interval: Interval) { const highlights = reactive([]) -const matrix = computed(() => intervalMatrix(scale.relativeIntervals)) +const matrix = computed(() => + intervalMatrix(scale.relativeIntervals.slice(0, state.maxMatrixWidth)) +) const matrixRows = computed(() => matrix.value.map((row) => row.map(formatMatrixCell))) @@ -124,6 +125,9 @@ const nedjiProjector = computed(() => { }) function highlight(y?: number, x?: number) { + if (!state.calculateConstantStructureViolations) { + return + } if (highlights.length !== matrix.value.length) { highlights.length = 0 for (let i = 0; i < matrix.value.length; ++i) { @@ -170,11 +174,11 @@ function highlight(y?: number, x?: number) { - - + - + - + - +
+ {{ i - 1 + state.intervalMatrixIndexing }} ({{ scale.scale.size + state.intervalMatrixIndexing }})Bright %Bright %
@@ -183,17 +187,20 @@ function highlight(y?: number, x?: number) { {{ name }} {{ brightness[i] }}{{ brightness[i] }}
Var {{ v }}
@@ -215,6 +222,11 @@ function highlight(y?: number, x?: number) { + +

+ More options +

+
@@ -227,6 +239,32 @@ function highlight(y?: number, x?: number) {
+
+ + +
+
+ + +
+
+ + +
+
+ + +
diff --git a/src/views/PreferencesView.vue b/src/views/PreferencesView.vue index 4210dcf2..953d467a 100644 --- a/src/views/PreferencesView.vue +++ b/src/views/PreferencesView.vue @@ -41,8 +41,8 @@ const scale = useScaleStore()
- +