Musical keyboard component written in React.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

47 line
1.5 KiB

  1. import isNaturalKey from './isNaturalKey'
  2. import groupKeysIntoOctaves from './groupKeysIntoOctaves'
  3. import getOctaveCompleteness from './getOctaveCompleteness'
  4. import getOctaveCount from './getOctaveCount'
  5. import generateKeys from './generateKeys'
  6. interface GetKeyWidth {
  7. (k: number): number,
  8. }
  9. interface GetKeyWidthDecorator {
  10. (startKey: number, endKey: number): GetKeyWidth,
  11. }
  12. const ACCIDENTAL_KEY_TO_NATURAL_KEY_WIDTH_RATIO = 18 / 36
  13. const getKeyWidthDecorator: GetKeyWidthDecorator = (startKey, endKey): GetKeyWidth => (k) => {
  14. const dummyKeys = generateKeys(startKey, endKey)
  15. const keysGroupedIntoOctaves = groupKeysIntoOctaves(dummyKeys)
  16. const octaveCompleteness = Object
  17. .entries(keysGroupedIntoOctaves)
  18. .map<number[]>(([octave, keys]) => [
  19. octave as unknown as number,
  20. keys[0],
  21. keys.slice(-1)[0],
  22. ])
  23. .reduce<Record<number, number>>(
  24. (theOctaveCompleteness, [octave, firstKey, lastKey]) => ({
  25. ...theOctaveCompleteness,
  26. [octave]: getOctaveCompleteness(firstKey, lastKey),
  27. }),
  28. {}
  29. )
  30. const fractionalOctaveCount = Object
  31. .values(octaveCompleteness)
  32. .reduce(
  33. (a, b) => a + b,
  34. 0
  35. )
  36. const octaveCount = getOctaveCount(startKey, endKey)
  37. const naturalKeyWidth = 100 * (octaveCount / fractionalOctaveCount) / (octaveCount * 7)
  38. return isNaturalKey(k) ? naturalKeyWidth : naturalKeyWidth * ACCIDENTAL_KEY_TO_NATURAL_KEY_WIDTH_RATIO // naturalKeyWidth * 13.7 / 23.5}
  39. }
  40. export default getKeyWidthDecorator