parseABC.ts 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. /**
  2. * 解析ABC曲谱, 获取最小的音符单位
  3. * @param abcNotation abc曲谱
  4. * @returns 最小的音符单位
  5. */
  6. export const getMinNoteUnit = (abcNotation: string) => {
  7. const lines = abcNotation.split("\n");
  8. let minNoteUnit = null;
  9. for (const line of lines) {
  10. const regex = /L:(\s*)(\d+\/\d+)/;
  11. const match = line.match(regex);
  12. console.log("🚀 ~ line:", line, match);
  13. // Extract the unit note length from the L: directive.
  14. const unitNoteLengthMatch = line.match(regex);
  15. if (unitNoteLengthMatch) {
  16. minNoteUnit = unitNoteLengthMatch[unitNoteLengthMatch.length - 1];
  17. break;
  18. }
  19. }
  20. return minNoteUnit;
  21. };
  22. // Convert an AudioBuffer to a Blob using WAVE representation
  23. export const bufferToWave = (audioBuffer: AudioBuffer) => {
  24. var numOfChan = audioBuffer.numberOfChannels;
  25. var length = audioBuffer.length * numOfChan * 2 + 44;
  26. var buffer = new ArrayBuffer(length);
  27. var view = new DataView(buffer);
  28. var channels = [];
  29. var i;
  30. var sample;
  31. var offset = 0;
  32. var pos = 0;
  33. // write WAVE header
  34. setUint32(0x46464952); // "RIFF"
  35. setUint32(length - 8); // file length - 8
  36. setUint32(0x45564157); // "WAVE"
  37. setUint32(0x20746d66); // "fmt " chunk
  38. setUint32(16); // length = 16
  39. setUint16(1); // PCM (uncompressed)
  40. setUint16(numOfChan);
  41. setUint32(audioBuffer.sampleRate);
  42. setUint32(audioBuffer.sampleRate * 2 * numOfChan); // avg. bytes/sec
  43. setUint16(numOfChan * 2); // block-align
  44. setUint16(16); // 16-bit (hardcoded in this demo)
  45. setUint32(0x61746164); // "data" - chunk
  46. setUint32(length - pos - 4); // chunk length
  47. // write interleaved data
  48. for(i = 0; i < numOfChan; i++)
  49. channels.push(audioBuffer.getChannelData(i));
  50. while(pos < length) {
  51. for(i = 0; i < channels.length; i++) { // interleave channels
  52. sample = Math.max(-1, Math.min(1, channels[i][offset])); // clamp
  53. sample = (0.5 + sample < 0 ? sample * 32768 : sample * 32767)|0; // scale to 16-bit signed int
  54. view.setInt16(pos, sample, true); // write 16-bit sample
  55. pos += 2;
  56. }
  57. offset++; // next source sample
  58. }
  59. // create Blob
  60. return new Blob([buffer], {type: "audio/wav"});
  61. function setUint16(data: any) {
  62. view.setUint16(pos, data, true);
  63. pos += 2;
  64. }
  65. function setUint32(data: any) {
  66. view.setUint32(pos, data, true);
  67. pos += 4;
  68. }
  69. }