Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply CS margin to variety signature on Analysis tab. #797

Merged
merged 1 commit into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Change log

## 3.0.1
* Feature: Apply CS margin to variety signature on Analysis tab [#796](https://github.com/xenharmonic-devs/scale-workshop/issues/796)
* Feature: Approximate Tenney-tall fractions on Analysis tab [#796](https://github.com/xenharmonic-devs/scale-workshop/issues/796)
* Regression: Show pitch associated with MIDI base index [#795](https://github.com/xenharmonic-devs/scale-workshop/issues/795)

## 3.0.0
Expand Down
22 changes: 22 additions & 0 deletions src/analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,28 @@ export function varietySignature(matrix: Interval[][]) {
return result
}

export function marginVarietySignature(centsMatrix: number[][], margin: number) {
const result: number[] = []
if (!centsMatrix.length) {
return result
}
for (let i = 0; i < centsMatrix[0].length; ++i) {
let variety = 1
for (let j = 1; j < centsMatrix.length; ++j) {
variety++
const cents = centsMatrix[j][i]
for (let k = 0; k < j; ++k) {
if (Math.abs(centsMatrix[k][i] - cents) < margin) {
variety--
break
}
}
}
result.push(variety)
}
return result
}

export function brightnessSignature(centsMatrix: number[][]) {
const totals = centsMatrix.map((row) => row.reduce((prev, cur) => prev + cur, 0))
const minimum = Math.min(...totals)
Expand Down
36 changes: 25 additions & 11 deletions src/views/AnalysisView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
constantStructureViolations,
freeEquallyTemperedChord,
intervalMatrix,
marginVarietySignature,
marginViolations,
rootedEquallyTemperedChord,
varietySignature
Expand Down Expand Up @@ -31,6 +32,7 @@ const entropy = useHarmonicEntropyStore()
const subtab = ref<'matrix' | 'wheels' | 'entropy'>('matrix')
const cellFormat = ref<'best' | 'fraction' | 'cents' | 'et' | 'decimal'>('best')
const simplifyTolerance = ref(3.5)
const fractionMaxHeight = ref(26)
const showOptions = ref(false)
const trailLongevity = ref(70)
const maxOtonalRoot = ref(16)
Expand Down Expand Up @@ -86,31 +88,34 @@ const etDenominator = computed(() => {
// While interval.name suffices for the tuning table
// we want more accurate results here.
function formatMatrixCell(interval: Interval) {
const monzo = interval.value
if (cellFormat.value === 'fraction') {
if (interval.value.isFractional()) {
const node = interval.value.asFractionLiteral()
if (
monzo.isFractional() &&
(!fractionMaxHeight.value || monzo.tenneyHeight() < fractionMaxHeight.value)
) {
const node = monzo.asFractionLiteral()
if (node) {
return literalToString(node)
}
}
try {
return (
'~' +
new Fraction(interval.valueOf()).simplifyRelative(simplifyTolerance.value).toFraction()
'~' + new Fraction(monzo.valueOf()).simplifyRelative(simplifyTolerance.value).toFraction()
)
} catch {
return '?'
}
}
if (cellFormat.value === 'cents') {
return interval.totalCents(true).toFixed(1)
return monzo.totalCents(true).toFixed(1)
}
if (cellFormat.value === 'decimal') {
// Consistent with tuning table localization.
return interval.valueOf().toFixed(3)
return monzo.valueOf().toFixed(3)
}
if (cellFormat.value === 'et') {
const fractionOfEquave = interval.value.log(scaleEquave.value)
const fractionOfEquave = monzo.log(scaleEquave.value)
if (typeof fractionOfEquave === 'number') {
return `~${Math.round(fractionOfEquave * 100)}%`
}
Expand Down Expand Up @@ -139,12 +144,17 @@ const violations = computed(() => {
const margin = state.constantStructureMargin
if (margin) {
return marginViolations(centsMatrix.value, margin)
} else {
return constantStructureViolations(matrix.value)
}
return constantStructureViolations(matrix.value)
})

const variety = computed(() => varietySignature(matrix.value))
const variety = computed(() => {
const margin = state.constantStructureMargin
if (margin) {
return marginVarietySignature(centsMatrix.value, margin)
}
return varietySignature(matrix.value)
})

const brightness = computed(() =>
brightnessSignature(centsMatrix.value).map((b) => Math.round(100 * b))
Expand Down Expand Up @@ -408,6 +418,10 @@ const sSlider = computed({
v-model="simplifyTolerance"
/>
</div>
<div class="control">
<label for="fraction-max-height">Fraction maximum Tenney height in nats (0 = off)</label>
<input id="fraction-max-height" type="number" min="0" v-model="fractionMaxHeight" />
</div>
<div class="control">
<label for="max-matrix-width">Maximum matrix width</label>
<input
Expand All @@ -427,7 +441,7 @@ const sSlider = computed({
<label for="calculate-violators">Show constant structure violations</label>
</div>
<div class="control">
<label for="cs-margin">Constant structure margin in cents</label>
<label for="cs-margin">Constant structure / variety margin in cents</label>
<input id="cs-margin" type="number" min="0" v-model="state.constantStructureMargin" />
</div>
<div class="control checkbox-container">
Expand Down
Loading