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.
 
 
 
 

49 line
1.3 KiB

  1. import * as React from 'react'
  2. import SoundGenerator from '../services/SoundGenerator'
  3. type ChangeProps = {
  4. setChannel(channel: number): void
  5. }
  6. type Change = (props: ChangeProps) => React.ChangeEventHandler<HTMLInputElement>
  7. export const change: Change = ({ setChannel }) => e => {
  8. const { value: rawValue } = e.target
  9. const value = Number(rawValue)
  10. setChannel(value)
  11. }
  12. type KeyChannel = {
  13. key: number,
  14. velocity: number,
  15. channel: number,
  16. }
  17. type KeyChannelCallback = (oldKeys: KeyChannel[]) => KeyChannel[]
  18. type HandleProps = {
  19. setKeyChannels(callback: KeyChannelCallback | KeyChannel[]): void,
  20. generator?: SoundGenerator,
  21. }
  22. type Handle = (props: HandleProps) => (newKeys: KeyChannel[]) => void
  23. export const handle: Handle = ({ setKeyChannels, generator, }) => newKeys => {
  24. setKeyChannels((oldKeys) => {
  25. if (generator! !== undefined) {
  26. const oldKeysKeys = oldKeys.map((k) => k.key)
  27. const newKeysKeys = newKeys.map((k) => k.key)
  28. const keysOff = oldKeys.filter((ok) => !newKeysKeys.includes(ok.key))
  29. const keysOn = newKeys.filter((nk) => !oldKeysKeys.includes(nk.key))
  30. keysOn.forEach((k) => {
  31. generator.noteOn(k.channel, k.key, Math.floor(k.velocity * 127))
  32. })
  33. keysOff.forEach((k) => {
  34. generator.noteOff(k.channel, k.key, Math.floor(k.velocity * 127))
  35. })
  36. }
  37. return newKeys
  38. })
  39. }