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

Use only a single source of truth for base frequency #659

Merged
merged 1 commit into from
Apr 18, 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: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
* Feature: Implement multi-channel MIDI mode compatible with the Lumatone [#649](https://github.com/xenharmonic-devs/scale-workshop/pull/649)
* Bug fix: Extreme ratios now only break parts of the tuning table that do not have IEEE floating point representation and format better when non-finite [#631](https://github.com/xenharmonic-devs/scale-workshop/issues/631), [#632](https://github.com/xenharmonic-devs/scale-workshop/issues/632)
* Style fix: Make checkbox and radio button labels more consistent [#644](https://github.com/xenharmonic-devs/scale-workshop/issues/644)
* Beta cycle issues: [#643](https://github.com/xenharmonic-devs/scale-workshop/issues/643), [#640](https://github.com/xenharmonic-devs/scale-workshop/issues/640), [#577](https://github.com/xenharmonic-devs/scale-workshop/issues/577), [#513](https://github.com/xenharmonic-devs/scale-workshop/issues/513)
* Beta cycle issues: [#643](https://github.com/xenharmonic-devs/scale-workshop/issues/643), [#640](https://github.com/xenharmonic-devs/scale-workshop/issues/640), [#577](https://github.com/xenharmonic-devs/scale-workshop/issues/577), [#513](https://github.com/xenharmonic-devs/scale-workshop/issues/513), [#658](https://github.com/xenharmonic-devs/scale-workshop/issues/658)
* 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
Expand Down
6 changes: 3 additions & 3 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ function typingKeydown(event: CoordinateKeyboardEvent) {
return emptyKeyup
}

let index = scale.baseMidiNote + scale.scale.size * scale.equaveShift + scale.degreeShift
let index = scale.scale.baseMidiNote + scale.scale.size * scale.equaveShift + scale.degreeShift

if (scale.keyboardMode === 'isomorphic') {
index += x * state.isomorphicHorizontal + (2 - y) * state.isomorphicVertical
Expand Down Expand Up @@ -351,7 +351,7 @@ onMounted(() => {
const scaleWorkshopOneData = new ScaleWorkshopOneData()

scale.name = scaleWorkshopOneData.name
scale.baseFrequency = scaleWorkshopOneData.freq
scale.userBaseFrequency = scaleWorkshopOneData.freq
scale.autoFrequency = false
scale.baseMidiNote = scaleWorkshopOneData.midi
state.isomorphicHorizontal = scaleWorkshopOneData.horizontal
Expand Down Expand Up @@ -389,7 +389,7 @@ onMounted(() => {
}

scale.name = decodedState.scaleName
scale.baseFrequency = decodedState.baseFrequency
scale.userBaseFrequency = decodedState.baseFrequency
scale.autoFrequency = false
scale.baseMidiNote = decodedState.baseMidiNote
state.isomorphicHorizontal = decodedState.isomorphicHorizontal
Expand Down
8 changes: 0 additions & 8 deletions src/components/ExporterButtons.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ function doExport(exporter: ExporterKey) {
scaleUrl: window.location.href,
filename: sanitizeFilename(scale.name),
relativeIntervals: scale.relativeIntervals,
baseFrequency: scale.baseFrequency,
baseMidiNote: scale.baseMidiNote,
scale: scale.scale,
labels: scale.labels,
midiOctaveOffset: -1,
Expand All @@ -68,8 +66,6 @@ function doExport(exporter: ExporterKey) {
@cancel="showKorgExportModal = false"
:newline="state.newline"
:scaleName="scale.name"
:baseMidiNote="scale.baseMidiNote"
:baseFrequency="scale.baseFrequency"
:relativeIntervals="scale.relativeIntervals"
:midiOctaveOffset="-1"
:scale="scale.scale"
Expand All @@ -82,8 +78,6 @@ function doExport(exporter: ExporterKey) {
@cancel="showMtsSysexExportModal = false"
:newline="state.newline"
:scaleName="scale.name"
:baseMidiNote="scale.baseMidiNote"
:baseFrequency="scale.baseFrequency"
:relativeIntervals="scale.relativeIntervals"
:midiOctaveOffset="-1"
:scale="scale.scale"
Expand All @@ -96,8 +90,6 @@ function doExport(exporter: ExporterKey) {
@cancel="showReaperExportModal = false"
:newline="state.newline"
:scaleName="scale.name"
:baseMidiNote="scale.baseMidiNote"
:baseFrequency="scale.baseFrequency"
:relativeIntervals="scale.relativeIntervals"
:midiOctaveOffset="-1"
:scale="scale.scale"
Expand Down
2 changes: 1 addition & 1 deletion src/components/NewScale.vue
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ function blur() {
}

function updateBaseFrequency(value: number) {
scale.baseFrequency = value
scale.userBaseFrequency = value
scale.autoFrequency = false
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/ScaleControls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ defineExpose({ focus, clearPaletteInfo })
id="base-frequency"
type="number"
step="any"
v-model="scale.baseFrequency"
v-model="scale.baseFrequencyDisplay"
:disabled="scale.autoFrequency"
@input="updateScale"
/>
Expand Down
4 changes: 0 additions & 4 deletions src/components/modals/export/KorgExport.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import type { Scale } from '@/scale'
const props = defineProps<{
newline: string
scaleName: string
baseMidiNote: number
baseFrequency: number
midiOctaveOffset: number
relativeIntervals: Interval[]
labels: string[]
Expand Down Expand Up @@ -50,9 +48,7 @@ async function doExport() {
scale: props.scale,
relativeIntervals: props.relativeIntervals,
labels: props.labels,
baseFrequency: props.baseFrequency,
filename: sanitizeFilename(props.scaleName),
baseMidiNote: props.baseMidiNote,
midiOctaveOffset: props.midiOctaveOffset
}

Expand Down
4 changes: 0 additions & 4 deletions src/components/modals/export/MtsSysexExport.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import type { Interval } from 'sonic-weave'
const props = defineProps<{
newline: string
scaleName: string
baseMidiNote: number
baseFrequency: number
midiOctaveOffset: number
relativeIntervals: Interval[]
scale: Scale
Expand Down Expand Up @@ -58,8 +56,6 @@ function doExport() {
newline: props.newline,
scale: props.scale,
filename: sanitizeFilename(props.scaleName),
baseMidiNote: props.baseMidiNote,
baseFrequency: props.baseFrequency,
relativeIntervals: props.relativeIntervals,
midiOctaveOffset: props.midiOctaveOffset,
labels: props.labels,
Expand Down
4 changes: 0 additions & 4 deletions src/components/modals/export/ReaperExport.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import type { Interval } from 'sonic-weave'
const props = defineProps<{
newline: string
scaleName: string
baseMidiNote: number
baseFrequency: number
midiOctaveOffset: number
relativeIntervals: Interval[]
scale: Scale
Expand Down Expand Up @@ -39,8 +37,6 @@ function doExport() {
newline: props.newline,
scale: props.scale,
filename: sanitizeFilename(props.scaleName),
baseMidiNote: props.baseMidiNote,
baseFrequency: props.baseFrequency,
midiOctaveOffset: props.midiOctaveOffset,
relativeIntervals: props.relativeIntervals,
labels: props.labels,
Expand Down
2 changes: 0 additions & 2 deletions src/exporters/__tests__/test-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@ export function getTestData(appTitle: string) {
scale,
appTitle,
description: 'A scale for testing if the exporter works',
baseMidiNote: 69,
baseFrequency: 440,
midiOctaveOffset: 0,
sourceText: '100.\nC5_5\n4\\5\n5/3\n1,3591409142295225r\n3486784401/3276800000\n2/1',
labels: ['100.', 'C5_5', '4\\5', '5/3', '1,3591409142295225r', '3486784401/3276800000', '2/1'],
Expand Down
4 changes: 2 additions & 2 deletions src/exporters/ableton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default class AbletonAsclExporter extends BaseExporter {
const newline = this.params.newline
const intervals = this.params.relativeIntervals
const labels = this.params.labels
const referenceFrequency = this.params.baseFrequency.toFixed(8)
const referenceFrequency = this.params.scale.baseFrequency.toFixed(8)
// assemble the .ascl file contents
let file = '! ' + this.params.filename + '.ascl' + newline
file += '! Created using ' + this.appTitle + newline
Expand Down Expand Up @@ -59,7 +59,7 @@ export default class AbletonAsclExporter extends BaseExporter {
}

// It's unclear what "octave number" means in the spec
const octave = Math.floor(ftom(this.params.baseFrequency)[0] / 12) - 1
const octave = Math.floor(ftom(this.params.scale.baseFrequency)[0] / 12) - 1

file += '!' + newline
file += '! @ABL NOTE_NAMES ' + names.join(' ') + newline
Expand Down
3 changes: 1 addition & 2 deletions src/exporters/anamark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,7 @@ class AnaMarkExporter extends BaseExporter {
newline +
'; Set reference key to absolute frequency (not scale note but midi key)' +
newline
file +=
'note ' + this.params.baseMidiNote + '="! ' + scale.baseFrequency.toFixed(6) + '"' + newline
file += 'note ' + scale.baseMidiNote + '="! ' + scale.baseFrequency.toFixed(6) + '"' + newline
}

file += newline + '[Scale End]' + newline
Expand Down
2 changes: 0 additions & 2 deletions src/exporters/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ export type ExporterParams = {
newline: string
filename: string
relativeIntervals: Interval[]
baseFrequency: number
baseMidiNote: number
midiOctaveOffset: number
scale: Scale
labels: string[]
Expand Down
2 changes: 1 addition & 1 deletion src/exporters/image-line.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class ImageLineExporter extends BaseExporter {
getFileContents(range: number) {
const scale = this.params.scale

const baseFreqOffset = Math.log2(this.params.baseFrequency / 440) // in number of octaves
const baseFreqOffset = Math.log2(this.params.scale.baseFrequency / 440) // in number of octaves

// construct point data
const points = new ArrayBuffer(121 * 24)
Expand Down
4 changes: 2 additions & 2 deletions src/exporters/kontakt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default class KontaktExporter extends BaseExporter {

getFileContents() {
const newline = this.params.newline
const baseMidiNote = this.params.baseMidiNote
const baseMidiNote = this.params.scale.baseMidiNote

// assemble the kontakt script contents
let file = '{**************************************' + newline
Expand All @@ -30,7 +30,7 @@ export default class KontaktExporter extends BaseExporter {
' (' +
midiNoteNumberToName(baseMidiNote, this.params.midiOctaveOffset) +
') = ' +
this.params.baseFrequency.toString() +
this.params.scale.baseFrequency.toString() +
' Hz' +
newline
file += 'Created using ' + this.appTitle + newline + newline
Expand Down
4 changes: 2 additions & 2 deletions src/exporters/korg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,12 @@ export class KorgExporter extends BaseExporter {

getFileContents(): [JSZip, string] {
const scale = this.params.scale
const baseMidiNote = this.params.baseMidiNote
const baseMidiNote = scale.baseMidiNote

let frequencies: number[]
if (this.useOctaveFormat) {
const rootFreq = mtof(0)
const transposeRatio = rootFreq / this.params.baseFrequency
const transposeRatio = rootFreq / scale.baseFrequency
frequencies = scale
.getFrequencyRange(baseMidiNote, baseMidiNote + OCTAVE_FORMAT_SIZE)
.map((f: number) => f * transposeRatio)
Expand Down
4 changes: 2 additions & 2 deletions src/exporters/reaper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default class ReaperExporter extends BaseExporter {
const digits = ReaperExporter.fractionDigits
const scale = this.params.scale
const labels = this.params.labels
const baseFrequency = this.params.baseFrequency
const baseFrequency = scale.baseFrequency
const format = this.params.format
const basePeriod = this.params.basePeriod || 0
const baseDegree = this.params.baseDegree || 0
Expand All @@ -27,7 +27,7 @@ export default class ReaperExporter extends BaseExporter {
for (let i = ReaperExporter.tuningMaxSize - 1; i >= 0; i--) {
file += i.toString() + ' '

let index = i - this.params.baseMidiNote
let index = i - scale.baseMidiNote
const period = basePeriod + Math.floor(index / scale.size)
if (modBySize) {
index = mmod(index, scale.size)
Expand Down
7 changes: 4 additions & 3 deletions src/exporters/scala.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ export class ScalaKbmExporter extends BaseExporter {
getFileContents() {
const newline = this.params.newline
const intervals = this.params.relativeIntervals
const baseFrequency = this.params.baseFrequency
const baseFrequency = this.params.scale.baseFrequency
const baseMidiNote = this.params.scale.baseMidiNote
// assemble the .kbm file contents
let file = '! Template for a keyboard mapping' + newline
file += '!' + newline
Expand All @@ -74,9 +75,9 @@ export class ScalaKbmExporter extends BaseExporter {
file += '! Last MIDI note number to retune:' + newline
file += '127' + newline
file += '! Middle note where the first entry of the mapping is mapped to:' + newline
file += this.params.baseMidiNote.toString() + newline
file += baseMidiNote.toString() + newline
file += '! Reference note for which frequency is given:' + newline
file += this.params.baseMidiNote.toString() + newline
file += baseMidiNote.toString() + newline
file += '! Frequency to tune the above note to' + newline
file += baseFrequency.toString() + newline
file += '! Scale degree to consider as formal octave (determines difference in pitch' + newline
Expand Down
16 changes: 12 additions & 4 deletions src/stores/scale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,30 @@ export const useScaleStore = defineStore('scale', () => {
const gas = ref(parseInt(localStorage.getItem('gas') ?? '10000', 10))

const name = ref('')
// For the v-model. Consider stores.scale.scale.baseMidiNote the source of truth.
const baseMidiNote = ref(60)

// The concept of base frequency is a little confusing so here's an explanation:
// The user can either set the base frequency or have it be automatically calculated.
// baseFrequencyDisplay reflects the initial value passed to the SonicWeave runtime.
// However the runtime may assign a different unison frequency and that's what ends up in scale.value.baseFrequency.
// Threrefore stores.scale.scale.baseFrequency is the source of truth, while stores.scale.baseFrequencyDisplay is the v-model.
const userBaseFrequency = ref(261.63)
const autoFrequency = ref(true)
const baseFrequency = computed({
const baseFrequencyDisplay = computed({
get() {
return autoFrequency.value ? mtof(baseMidiNote.value) : userBaseFrequency.value
},
set(value: number) {
userBaseFrequency.value = value
}
})
// XXX: baseFrequencyDisplay is merely used for convenience here. This is the last time there's a direct connection.
const scale = ref(new Scale(TET12, baseFrequencyDisplay.value, baseMidiNote.value))
const autoColors = ref<'silver' | 'cents' | 'factors'>('silver')
const sourceText = ref('')
const relativeIntervals = ref(INTERVALS_12TET)
const latticeIntervals = ref(INTERVALS_12TET)
const scale = ref(new Scale(TET12, baseFrequency.value, baseMidiNote.value))
const colors = ref(defaultColors(baseMidiNote.value))
const labels = ref(defaultLabels(baseMidiNote.value, accidentalPreference.value))
const error = ref('')
Expand Down Expand Up @@ -302,7 +310,7 @@ export const useScaleStore = defineStore('scale', () => {
// Inject global variables
const _ = Interval.fromInteger(baseMidiNote.value)
const baseFreq = new Interval(
TimeMonzo.fromFractionalFrequency(new Fraction(baseFrequency.value).simplify(1e-8)),
TimeMonzo.fromFractionalFrequency(new Fraction(baseFrequencyDisplay.value).simplify(1e-8)),
'linear'
)
const extraBuiltins: Record<string, SonicWeaveValue> = {
Expand Down Expand Up @@ -433,7 +441,7 @@ export const useScaleStore = defineStore('scale', () => {
userBaseFrequency,
autoFrequency,
autoColors,
baseFrequency,
baseFrequencyDisplay,
sourcePrefix,
sourceText,
scale,
Expand Down
2 changes: 1 addition & 1 deletion src/views/AnalysisView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const heldScaleDegrees = computed(() => {
const result: Set<number> = new Set()
for (const midiIndex of state.heldNotes.keys()) {
if (state.heldNotes.get(midiIndex)! > 0) {
result.add(mmod(midiIndex - scale.baseMidiNote, scale.scale.size))
result.add(mmod(midiIndex - scale.scale.baseMidiNote, scale.scale.size))
}
}
return result
Expand Down
2 changes: 1 addition & 1 deletion src/views/LatticeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const heldNotes = computed(() => {
for (const midiIndex of state.heldNotes.keys()) {
if (state.heldNotes.get(midiIndex)! > 0) {
// Offset by 1 to match relativeIntervals
result.add(perm[mmod(midiIndex - scale.baseMidiNote - 1, scale.scale.size)])
result.add(perm[mmod(midiIndex - scale.scale.baseMidiNote - 1, scale.scale.size)])
}
}
return result
Expand Down
4 changes: 2 additions & 2 deletions src/views/ScaleView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ onMounted(() => {
:heldNotes="state.heldNotes"
:frequencies="scale.frequencies"
:centss="scale.centss"
:baseFrequency="scale.baseFrequency"
:baseMidiNote="scale.baseMidiNote"
:baseFrequency="scale.scale.baseFrequency"
:baseMidiNote="scale.scale.baseMidiNote"
:colors="scale.colors"
:labels="scale.labels"
/>
Expand Down
6 changes: 3 additions & 3 deletions src/views/VirtualKeyboardView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const state = useStateStore()
const scale = useScaleStore()

const baseIndex = computed(
() => scale.baseMidiNote + scale.equaveShift * scale.scale.size + scale.degreeShift
() => scale.scale.baseMidiNote + scale.equaveShift * scale.scale.size + scale.degreeShift
)

type NoteOff = () => void
Expand All @@ -25,7 +25,7 @@ type NoteOnCallback = (index: number) => NoteOff
<VirtualPiano
v-if="scale.keyboardMode === 'piano'"
:baseIndex="baseIndex"
:baseMidiNote="scale.baseMidiNote"
:baseMidiNote="scale.scale.baseMidiNote"
:colorMap="scale.colorForIndex"
:splitAccidentals="scale.splitAccidentals"
:accidentalColor="scale.accidentalColor"
Expand All @@ -38,7 +38,7 @@ type NoteOnCallback = (index: number) => NoteOff
<VirtualKeyboard
v-else
:baseIndex="baseIndex"
:baseMidiNote="scale.baseMidiNote"
:baseMidiNote="scale.scale.baseMidiNote"
:isomorphicHorizontal="state.isomorphicHorizontal"
:isomorphicVertical="state.isomorphicVertical"
:keyColors="scale.colors"
Expand Down
2 changes: 1 addition & 1 deletion src/views/VirtualQwerty.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ defineProps<{
}>()

const baseIndex = computed(
() => scale.baseMidiNote + scale.equaveShift * scale.scale.size + scale.degreeShift
() => scale.scale.baseMidiNote + scale.equaveShift * scale.scale.size + scale.degreeShift
)
</script>

Expand Down
Loading