tick.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. import { reactive } from 'vue';
  2. import tockAndTick from './tockAndTick.json';
  3. import { Howl } from 'howler';
  4. import { initSelectScorePart, initSelectScorePartModal, setting, setting_modal } from './setting';
  5. import { beatDesc } from './beat-desc';
  6. const tickData = reactive({
  7. list: [] as number[],
  8. len: 0, // 有几拍
  9. afterBeat: 0, // 一小节里面有几拍
  10. tickEnd: false,
  11. /** 节拍器时间 */
  12. beatLengthInMilliseconds: 0,
  13. state: '',
  14. source1: '' as any,
  15. source2: '' as any,
  16. index: 0,
  17. show: false
  18. });
  19. // console.log(setting, 'setting')
  20. let defaultSetting = {
  21. // playState: setting.playState,
  22. // speed: setting.speed,
  23. // scorePart: setting.scorePart
  24. } as any
  25. let diffTime = 0; // 每一次节拍时间差
  26. const handlePlay = (i: number, source: any) => {
  27. let payBeatTime = new Date().getTime();
  28. return new Promise(resolve => {
  29. if (tickData.tickEnd) {
  30. resolve(i);
  31. return;
  32. }
  33. let timeSppedEnum = 16.7;
  34. const proofTime = () => {
  35. if (defaultSetting.playState !== 'play') {
  36. return;
  37. }
  38. setTimeout(() => {
  39. if (tickData.tickEnd) {
  40. resolve(i);
  41. return;
  42. }
  43. const currentTime = new Date().getTime();
  44. // 两次定时任务时间间隔
  45. const diffTime = currentTime - payBeatTime;
  46. if (diffTime >= tickData.beatLengthInMilliseconds) {
  47. tickData.index++;
  48. if (source) source.play();
  49. resolve(i);
  50. payBeatTime = currentTime;
  51. } else {
  52. if (
  53. Math.abs(diffTime - tickData.beatLengthInMilliseconds) <=
  54. timeSppedEnum
  55. ) {
  56. // 为了处理最后循环时间,用循环耗时
  57. for (let index = 0; index < 500000; index++) {
  58. let forTime = new Date().getTime();
  59. if (
  60. Math.abs(forTime - payBeatTime) >=
  61. tickData.beatLengthInMilliseconds
  62. ) {
  63. tickData.index++;
  64. if (source) source.play();
  65. resolve(i);
  66. payBeatTime = forTime;
  67. break;
  68. }
  69. }
  70. } else {
  71. proofTime();
  72. }
  73. }
  74. }, timeSppedEnum);
  75. };
  76. proofTime();
  77. });
  78. };
  79. /** 设置节拍器
  80. * @param beatLengthInMilliseconds 节拍间隔时间
  81. * @param beat 节拍数
  82. */
  83. export const handleInitTick = (
  84. beatLengthInMilliseconds: number,
  85. beat: number,
  86. afterBeat: number
  87. ) => {
  88. tickData.state = '';
  89. tickData.beatLengthInMilliseconds = beatLengthInMilliseconds;
  90. tickData.len = beat;
  91. tickData.afterBeat = afterBeat;
  92. };
  93. /** 开始节拍器
  94. * @param {boolean} 是否开启了设置
  95. */
  96. export const handleStartTick = async (settingStatus = false) => {
  97. const tempSetting = settingStatus ? setting_modal : setting
  98. defaultSetting = {
  99. playState: tempSetting.playState,
  100. speed: tempSetting.speed,
  101. scorePart: tempSetting.scorePart
  102. }
  103. tickData.show = true;
  104. tickData.tickEnd = false;
  105. if (tickData.state !== 'ok') {
  106. tickData.source1 = new Howl({
  107. src: tockAndTick.tick
  108. });
  109. tickData.source2 = new Howl({
  110. src: tockAndTick.tock
  111. });
  112. tickData.state = 'ok';
  113. }
  114. tickData.index = 0;
  115. tickData.beatLengthInMilliseconds = (60 / defaultSetting.speed) * 1000;
  116. if (tickData.afterBeat === 8) {
  117. tickData.beatLengthInMilliseconds = tickData.beatLengthInMilliseconds * 0.5;
  118. }
  119. for (let i = 0; i < defaultSetting.scorePart.length; i++) {
  120. if (tickData.tickEnd) return false;
  121. const temp = defaultSetting.scorePart[i];
  122. let len = temp.length;
  123. if (tickData.afterBeat === 8) {
  124. len = tickData.len;
  125. }
  126. for (let j = 0; j < len; j++) {
  127. // 提前结束, 直接放回false
  128. if (tickData.tickEnd) return false;
  129. const source =
  130. j === 0 ? tickData.source1 : j === len ? null : tickData.source2;
  131. await handlePlay(j, source);
  132. const tempJ = tickData.afterBeat === 8 ? Math.floor((j <= 0 ? 1 : j) / 3) : j
  133. if (settingStatus) {
  134. initSelectScorePartModal(i, tempJ)
  135. } else {
  136. initSelectScorePart(i, tempJ);
  137. }
  138. defaultSetting.playState = settingStatus ? setting_modal.playState : setting.playState
  139. if (defaultSetting.playState !== 'play') {
  140. hendleEndTick(settingStatus)
  141. }
  142. }
  143. }
  144. // console.log(+new Date() - startTime);
  145. tickData.show = false;
  146. handleStartTick(settingStatus);
  147. return true;
  148. };
  149. /** 节拍器暂停
  150. * @param {boolean} 是否开启了设置
  151. */
  152. export const hendleEndTick = (settingStatus = false) => {
  153. tickData.tickEnd = true;
  154. // 添加延期是因为播放时定时任务播放最多有16.7毫秒的延迟
  155. if (settingStatus) {
  156. initSelectScorePartModal()
  157. } else {
  158. initSelectScorePart();
  159. }
  160. };