Skip to content

Commit

Permalink
Merge pull request #426 from xenharmonic-devs/midi-octave-offset
Browse files Browse the repository at this point in the history
Make A4 the default reference pitch
  • Loading branch information
frostburn authored Nov 26, 2023
2 parents 95f834c + ec8c2f2 commit b8e4a31
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 6 deletions.
9 changes: 9 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ const colorScheme = ref<"light" | "dark">("light");
const centsFractionDigits = ref(3);
const decimalFractionDigits = ref(5);
const showVirtualQwerty = ref(false);
const midiOctaveOffset = ref(-1);
// Special keyboard codes also from local storage.
const deactivationCode = ref("Backquote");
Expand Down Expand Up @@ -748,6 +749,9 @@ onMounted(() => {
if ("showVirtualQwerty" in storage) {
showVirtualQwerty.value = storage.getItem("showVirtualQwerty") === "true";
}
if ("midiOctaveOffset" in storage) {
midiOctaveOffset.value = parseInt(storage.getItem("midiOctaveOffset")!);
}
// Fetch special key map
if ("deactivationCode" in storage) {
Expand Down Expand Up @@ -897,6 +901,9 @@ watch(decimalFractionDigits, (newValue) =>
watch(showVirtualQwerty, (newValue) =>
window.localStorage.setItem("showVirtualQwerty", newValue.toString())
);
watch(midiOctaveOffset, (newValue) =>
window.localStorage.setItem("midiOctaveOffset", newValue.toString())
);
// Store keymaps
watch(deactivationCode, (newValue) =>
window.localStorage.setItem("deactivationCode", newValue)
Expand Down Expand Up @@ -993,6 +1000,7 @@ watch(degreeDownCode, (newValue) =>
:typingKeyboard="typingKeyboard"
:keyboardMapping="keyboardMapping"
:showVirtualQwerty="showVirtualQwerty"
:midiOctaveOffset="midiOctaveOffset"
@update:audioDelay="audioDelay = $event"
@update:mainVolume="mainVolume = $event"
@update:scaleName="scaleName = $event"
Expand All @@ -1018,6 +1026,7 @@ watch(degreeDownCode, (newValue) =>
@update:centsFractionDigits="centsFractionDigits = $event"
@update:decimalFractionDigits="decimalFractionDigits = $event"
@update:showVirtualQwerty="showVirtualQwerty = $event"
@update:midiOctaveOffset="midiOctaveOffset = $event"
@update:deactivationCode="deactivationCode = $event"
@update:equaveUpCode="equaveUpCode = $event"
@update:equaveDownCode="equaveDownCode = $event"
Expand Down
7 changes: 6 additions & 1 deletion src/components/ScaleBuilder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ const props = defineProps<{
centsFractionDigits: number;
decimalFractionDigits: number;
newline: string;
midiOctaveOffset: number;
}>();
const emit = defineEmits([
Expand Down Expand Up @@ -129,6 +131,7 @@ function doExport(exporter: ExporterKey) {
scale: props.scale,
filename: sanitizeFilename(props.scaleName),
baseMidiNote: props.baseMidiNote,
midiOctaveOffset: props.midiOctaveOffset,
description: props.scaleName,
lines: props.scaleLines,
appTitle: APP_TITLE,
Expand Down Expand Up @@ -373,7 +376,9 @@ function copyToClipboard() {
step="1"
v-model="baseMidiNote"
/>
<span>{{ midiNoteNumberToName(baseMidiNote) }}</span>
<span>{{
midiNoteNumberToName(baseMidiNote, props.midiOctaveOffset)
}}</span>
</div>

<!-- This control is for the 3rd field that is found at the top of kbm files -->
Expand Down
1 change: 1 addition & 0 deletions src/exporters/__tests__/test-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export function getTestData(appTitle: string) {
appTitle,
description: "A scale for testing if the exporter works",
baseMidiNote: 69,
midiOctaveOffset: 0,
lines: [
"100.",
"4\\5",
Expand Down
1 change: 1 addition & 0 deletions src/exporters/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type ExporterParams = {
scale: Scale;
filename: string;
baseMidiNote: number;
midiOctaveOffset: number;
name?: string;
scaleUrl?: string;
description?: string;
Expand Down
2 changes: 1 addition & 1 deletion src/exporters/deflemask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default class DeflemaskExporter extends BaseExporter {
continue;

// convert note number to note name
let name = midiNoteNumberToName(noteNumber);
let name = midiNoteNumberToName(noteNumber, this.params.midiOctaveOffset);
name = name.length == 2 ? name.slice(0, 1) + "-" + name.slice(1) : name;

// convert cents offset to hex where -100c=00, 0c=80, 100c=FF
Expand Down
2 changes: 1 addition & 1 deletion src/exporters/kontakt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default class KontaktExporter extends BaseExporter {
"MIDI note " +
baseMidiNote.toString() +
" (" +
midiNoteNumberToName(baseMidiNote) +
midiNoteNumberToName(baseMidiNote, this.params.midiOctaveOffset) +
") = " +
this.params.scale.baseFrequency.toString() +
" Hz" +
Expand Down
11 changes: 8 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,15 @@ const MIDI_NOTE_NAMES = [
"B",
];

// Find MIDI note name from MIDI note number
export function midiNoteNumberToName(noteNumber: number) {
/**
* Convert an integer MIDI note number to a name such as A4.
* @param noteNumber MIDI note number to convert.
* @param octaveOffset Defaults to the English standard: 69 = A4. An offset of zero results in the French standard 69 = A5.
* @returns String representation of the MIDI note number.
*/
export function midiNoteNumberToName(noteNumber: number, octaveOffset = -1) {
const remainder = mmod(noteNumber, 12);
const quotient = (noteNumber - remainder) / 12;
const quotient = (noteNumber - remainder) / 12 + octaveOffset;
return MIDI_NOTE_NAMES[remainder] + quotient.toString();
}

Expand Down
16 changes: 16 additions & 0 deletions src/views/PreferencesView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const props = defineProps<{
centsFractionDigits: number;
decimalFractionDigits: number;
showVirtualQwerty: boolean;
midiOctaveOffset: number;
}>();
const emit = defineEmits([
Expand All @@ -17,6 +18,7 @@ const emit = defineEmits([
"update:decimalFractionDigits",
"update:virtualKeyboardMode",
"update:showVirtualQwerty",
"update:midiOctaveOffset",
]);
const newline = computed({
Expand All @@ -39,6 +41,10 @@ const showVirtualQwerty = computed({
get: () => props.showVirtualQwerty,
set: (newValue: boolean) => emit("update:showVirtualQwerty", newValue),
});
const midiOctaveOffset = computed({
get: () => props.midiOctaveOffset,
set: (newValue: number) => emit("update:midiOctaveOffset", newValue),
});
</script>

<template>
Expand Down Expand Up @@ -98,6 +104,16 @@ const showVirtualQwerty = computed({
<label for="scheme-dark"> Dark </label>
</span>
</div>
<div class="control">
<label for="midiOctaveOffset">MIDI octave offset</label>
<input
id="midiOctaveOffset"
type="number"
class="control"
step="1"
v-model="midiOctaveOffset"
/>
</div>
</div>
</div>
<div class="column">
Expand Down
3 changes: 3 additions & 0 deletions src/views/ScaleView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ defineProps<{
centsFractionDigits: number;
decimalFractionDigits: number;
newline: string;
midiOctaveOffset: number;
}>();
defineEmits([
Expand All @@ -38,6 +40,7 @@ defineEmits([
:centsFractionDigits="centsFractionDigits"
:decimalFractionDigits="decimalFractionDigits"
:newline="newline"
:midiOctaveOffset="midiOctaveOffset"
@update:scaleName="$emit('update:scaleName', $event)"
@update:scaleLines="$emit('update:scaleLines', $event)"
@update:scale="$emit('update:scale', $event)"
Expand Down

0 comments on commit b8e4a31

Please sign in to comment.