music-xml.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. export type FormatXMLResult = {
  2. xml: string
  3. speed: number
  4. partNames: string[]
  5. }
  6. /** 获取到xml前处理,添加额外的节拍 */
  7. export const fillBeatXML = (xml: string): string => {
  8. if (!xml) return ''
  9. const xmlParse = new DOMParser().parseFromString(xml, 'text/xml')
  10. const measures = xmlParse.getElementsByTagName('measure')
  11. // let speed = -1
  12. let beats = -1
  13. let beatType = -1
  14. // 小节中如果没有节点默认为休止符
  15. for (const measure of Array.from(measures)) {
  16. if (beats === -1 && measure.getElementsByTagName('beats').length) {
  17. beats = parseInt(
  18. measure.getElementsByTagName('beats')[0].textContent || '4'
  19. )
  20. }
  21. if (beatType === -1 && measure.getElementsByTagName('beat-type').length) {
  22. beatType = parseInt(
  23. measure.getElementsByTagName('beat-type')[0].textContent || '4'
  24. )
  25. }
  26. const divisions = parseInt(
  27. measure.getElementsByTagName('divisions')[0]?.textContent || '256'
  28. )
  29. if (measure.getElementsByTagName('note').length === 0) {
  30. const forwardTimeElement = measure
  31. .getElementsByTagName('forward')[0]
  32. ?.getElementsByTagName('duration')[0]
  33. if (forwardTimeElement) {
  34. forwardTimeElement.textContent = '0'
  35. }
  36. measure.innerHTML += `
  37. <note>
  38. <rest measure="yes"/>
  39. <duration>${divisions * beats}</duration>
  40. <voice>1</voice>
  41. <type>whole</type>
  42. </note>`
  43. }
  44. }
  45. return new XMLSerializer().serializeToString(xmlParse)
  46. }
  47. export type FormatXMLInfo = {
  48. speed: number
  49. title: string
  50. composer: string
  51. partNames: string[]
  52. }
  53. /** 获取xml基本信息,标题,速度等信息 */
  54. export const getXmlInfo = (xml: string): FormatXMLInfo => {
  55. const data: FormatXMLInfo = {
  56. /** 速度 */
  57. speed: 0,
  58. /** 标题 */
  59. title: '',
  60. /** 作曲人 */
  61. composer: '',
  62. /** 声部列表 */
  63. partNames: []
  64. }
  65. const xmlParse = new DOMParser().parseFromString(xml, 'text/xml')
  66. data.title = xmlParse.getElementsByTagName('work-title')[0]?.textContent || ''
  67. data.composer = xmlParse.getElementsByTagName('creator')[0]?.textContent || ''
  68. const measures = xmlParse.getElementsByTagName('measure')
  69. for (const item of Array.from(xmlParse.getElementsByTagName('part-name'))) {
  70. if (item.textContent) {
  71. data.partNames.push(item.textContent)
  72. }
  73. }
  74. for (const measure of Array.from(measures)) {
  75. const perMinute = measure.getElementsByTagName('per-minute')
  76. if (perMinute.length && perMinute[perMinute.length - 1]) {
  77. data.speed = parseFloat(
  78. perMinute[perMinute.length - 1].textContent || '0'
  79. )
  80. break
  81. }
  82. }
  83. return data
  84. }
  85. /** 解析xml */
  86. export const formatXMLFile = (file: File): FormatXMLResult => {
  87. console.log(file)
  88. const reader = new FileReader()
  89. reader.onload = e => {
  90. console.log(e)
  91. }
  92. reader.readAsText(file)
  93. return {
  94. xml: '',
  95. speed: 0,
  96. partNames: []
  97. }
  98. }