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

Collaboration to issue #534 #648

Merged
merged 2 commits into from
Apr 19, 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
46 changes: 46 additions & 0 deletions src/components/VirtualKeyInfo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<script setup lang="ts">
import { formatHertz, formatExponential, formatCents } from '@/utils'

const props = defineProps<{
label: string
cent: number
ratio: number
frequency: number
showLabel: boolean
showCent: boolean
showRatio: boolean
showFrequency: boolean
}>()
</script>

<template>
<div class="key-info">
<div v-if="props.showLabel">
<strong>{{ props.label }}</strong>
</div>
<div v-if="props.showCent">{{ formatCents(props.cent, 0) }}</div>
<div v-if="props.showRatio">{{ formatExponential(props.ratio) }}</div>
<div v-if="props.showFrequency">{{ formatHertz(props.frequency) }}</div>
</div>
</template>

<style scoped>
.key-info {
font-size: 1.25em;
text-shadow: 1px 1px 1px rgba(255, 255, 255, 0.3);
}

[data-theme='dark'] .key-info {
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
}

.black-key .key-info {
color: white;
text-shadow: none;
}

.white-key .key-info {
color: black;
text-shadow: none;
}
</style>
45 changes: 40 additions & 5 deletions src/components/VirtualKeyboard.vue
Original file line number Diff line number Diff line change
@@ -1,42 +1,65 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import VirtualKeyboardKey from '@/components/VirtualKeyboardKey.vue'
import { mmod } from 'xen-dev-utils'
import VirtualKeyInfo from '@/components/VirtualKeyInfo.vue'

type NoteOff = () => void
type NoteOnCallback = (index: number) => NoteOff
type ColorMap = (index: number) => string
type LabelMap = (index: number) => string

const props = defineProps<{
baseIndex: number // Should incorporate equave shift
baseMidiNote: number
keyColors: string[]
isomorphicHorizontal: number
isomorphicVertical: number
noteOn: NoteOnCallback
heldNotes: Map<number, number>
baseFrequency: number
frequencies: number[]
centss: number[]
colorMap: ColorMap
labelMap: LabelMap
showLabel: boolean
showCent: boolean
showRatio: boolean
showFrequency: boolean
}>()

type VirtualKey = {
x: number
y: number
index: number
color: string
frequency: number
cent: number
ratio: number
label: string
}

const virtualKeys = computed(() => {
const colors = props.keyColors.length ? props.keyColors : ['white']
const horizontal = props.isomorphicHorizontal
const vertical = props.isomorphicVertical
const result: [number, VirtualKey[]][] = []
const inverseBaseFreq = 1 / props.baseFrequency
for (let y = 3; y >= -1; y--) {
const row = []
for (let x = 0; x <= 12; ++x) {
const index = props.baseIndex + x * horizontal + y * vertical
const color = props.colorMap(index)
const frequency = props.frequencies[index]
const cent = props.centss[index]
const ratio = frequency * inverseBaseFreq
const label = props.labelMap(index)
row.push({
x,
y,
index,
color: colors[mmod(index - props.baseMidiNote - 1, colors.length)]
color,
frequency,
cent,
ratio,
label
})
}
result.push([y, row])
Expand All @@ -63,7 +86,18 @@ const isMousePressed = ref(false)
:noteOn="() => noteOn(key.index)"
@press="isMousePressed = true"
@unpress="isMousePressed = false"
></VirtualKeyboardKey>
>
<VirtualKeyInfo
:label="key.label"
:cent="key.cent"
:ratio="key.ratio"
:frequency="key.frequency"
:showLabel="props.showLabel"
:showCent="props.showCent"
:showRatio="props.showRatio"
:showFrequency="props.showFrequency"
/>
</VirtualKeyboardKey>
</tr>
</table>
</template>
Expand All @@ -75,5 +109,6 @@ table {
width: 100%;
height: 100%;
min-width: 500px; /* this stops the keys getting too close together for portrait mobile users */
table-layout: fixed;
}
</style>
6 changes: 4 additions & 2 deletions src/components/VirtualKeyboardKey.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,17 @@ onUnmounted(() => {
<td
:data-key-number="index"
:style="'background-color:' + color"
:class="{ active }"
:class="{ active, 'black-key': color === 'black', 'white-key': color === 'white' }"
@touchstart="onTouchStart"
@touchend="onTouchEnd"
@touchcancel="onTouchEnd"
@mousedown="onMouseDown"
@mouseup="onMouseUp"
@mouseenter="onMouseEnter"
@mouseleave="onMouseLeave"
></td>
>
<slot></slot>
</td>
</template>

<style scoped>
Expand Down
12 changes: 12 additions & 0 deletions src/stores/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ 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')
const showKeyboardLabel = ref(storage.getItem('showKeyboardLabel') !== 'false')
const showKeyboardCents = ref(storage.getItem('showKeyboardCents') !== 'false')
const showKeyboardRatio = ref(storage.getItem('showKeyboardRatio') !== 'false')
const showKeyboardFrequency = ref(storage.getItem('showKeyboardFrequency') !== 'false')

// Analysis preferences
const intervalMatrixIndexing = ref(parseInt(storage.getItem('intervalMatrixIndexing') ?? '0', 10))
Expand All @@ -50,6 +54,10 @@ export const useStateStore = defineStore('state', () => {
centsFractionDigits,
decimalFractionDigits,
showVirtualQwerty,
showKeyboardLabel,
showKeyboardCents,
showKeyboardRatio,
showKeyboardFrequency,
intervalMatrixIndexing,
maxMatrixWidth,
calculateConstantStructureViolations,
Expand Down Expand Up @@ -84,6 +92,10 @@ export const useStateStore = defineStore('state', () => {
centsFractionDigits,
decimalFractionDigits,
showVirtualQwerty,
showKeyboardLabel,
showKeyboardCents,
showKeyboardRatio,
showKeyboardFrequency,
intervalMatrixIndexing,
maxMatrixWidth,
calculateConstantStructureViolations,
Expand Down
4 changes: 4 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,10 @@ export function autoKeyColors(size: number) {
return result
}

export function formatCents(x: number, fractionDigits = 3) {
return formatExponential(x, fractionDigits) + '¢'
}

/**
* Fill in the gaps of a parent scale (in white) with accidentals (in black).
* @param generatorPerPeriod Generator sizre divided by period size (in pitch space).
Expand Down
1 change: 1 addition & 0 deletions src/views/AboutView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const tagline = computed(() => TAGLINES[Math.floor(Math.random() * TAGLINES.leng
Forrest Cahoon - <i>developer</i> <br />
Videco - <i>developer</i> <br />
Inthar - <i>developer</i> <br />
Wilckerson Ganda - <i>developer</i> <br />
Marc Sabat - <i>developer / notation-hardware advisor</i> <br />
Kraig Grady - <i>lattice advisor</i> <br />
Abnormality - <i>quality assurance</i> <br />
Expand Down
25 changes: 25 additions & 0 deletions src/views/SynthView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,31 @@ onUnmounted(() => {
</div>
</template>
</div>
<template v-if="scale.keyboardMode === 'isomorphic'">
<h2>Keyboard notes</h2>
<div class="control-group" style="flex-direction: row; flex-wrap: wrap">
<div class="control checkbox-container">
<input id="keyboard-show-label" type="checkbox" v-model="state.showKeyboardLabel" />
<label for="keyboard-show-label">Display label</label>
</div>
<div class="control checkbox-container">
<input id="keyboard-show-cents" type="checkbox" v-model="state.showKeyboardCents" />
<label for="keyboard-show-cents">Display cents</label>
</div>
<div class="control checkbox-container">
<input id="keyboard-show-ratio" type="checkbox" v-model="state.showKeyboardRatio" />
<label for="keyboard-show-ratio">Display ratio</label>
</div>
<div class="control checkbox-container">
<input
id="keyboard-show-frequency"
type="checkbox"
v-model="state.showKeyboardFrequency"
/>
<label for="keyboard-show-frequency">Display frequency</label>
</div>
</div>
</template>
<template v-if="scale.keyboardMode === 'isomorphic'">
<h2>Isomorphic key mapping</h2>
<p>
Expand Down
10 changes: 9 additions & 1 deletion src/views/VirtualKeyboardView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,17 @@ type NoteOnCallback = (index: number) => NoteOff
:baseMidiNote="scale.scale.baseMidiNote"
:isomorphicHorizontal="state.isomorphicHorizontal"
:isomorphicVertical="state.isomorphicVertical"
:keyColors="scale.colors"
:colorMap="scale.colorForIndex"
:noteOn="noteOn"
:heldNotes="state.heldNotes"
:baseFrequency="scale.baseFrequency"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's been a beta API change and this store prop no longer exists. I'll still merge your PR and fix on main. Normal beta cycle churn, nothing to worry about.

:frequencies="scale.frequencies"
:centss="scale.centss"
:labelMap="scale.labelForIndex"
:showLabel="state.showKeyboardLabel"
:showCent="state.showKeyboardCents"
:showRatio="state.showKeyboardRatio"
:showFrequency="state.showKeyboardFrequency"
></VirtualKeyboard>
</main>
</template>
Loading