import { TheoryINote } from "../interface/TheoryINote"; import { TheoryBeats } from "../../beats/TheoryBeats"; import { TheoryMeasure } from "../../measure/TheoryMeasure"; import { TheoryMath } from "../../../util/TheoryMath"; import { TheoryConstant } from "../../../util/TheoryConstant"; /** * Onset 应该可以合并到 BasicNote 方法里面 */ export class TheoryOnset { private static processTieNoteOnset(currentNote: TheoryINote, previousNote: TheoryINote) { // 如果当前的note 是 tie, 那么当前的note的onset就应该跟前一个的note的onset一样 currentNote.originalOnset = currentNote.onset; currentNote.onset = previousNote.onset; } public static addNormalNoteOnset(noteList_: TheoryINote[], Measure_: TheoryMeasure, Beats_: TheoryBeats) { // 初始化 let measureOnsetArray = Measure_.getMeasureOnset(Beats_); let categoriesVoiceStaff: number[] = []; let staffVoiceArrayCluster: { [voiceKey: string]: TheoryINote[] } = {}; // 检测总共有多少个多声部 for (let i = 0; i < noteList_.length; i++) { let voice = noteList_[i].voice; if (categoriesVoiceStaff.indexOf(voice) < 0) { categoriesVoiceStaff.push(voice); } } // 把每个多声部当成一个object的key值 for (let i = 0; i < categoriesVoiceStaff.length; i++) { staffVoiceArrayCluster[categoriesVoiceStaff[i]] = []; } // 把相同给的voice值的note给存在一个object里面 key-value noteList_.forEach((note) => { for (const voiceKey in staffVoiceArrayCluster) { if (staffVoiceArrayCluster.hasOwnProperty(voiceKey)) { const voice = note.voice; if (voice === parseInt(voiceKey, 10)) { staffVoiceArrayCluster[voiceKey].push(note); } } } }); // 每个小节累计有多少个小节 let beatsAccumulationOneSystem = 0; // 开始每个voice list for (const voiceKey in staffVoiceArrayCluster) { if (staffVoiceArrayCluster.hasOwnProperty(voiceKey)) { staffVoiceArrayCluster[voiceKey].sort((a, b) => a.xmlID - b.xmlID); // 开始每个voice list 里面的每一个note for (let i = 0; i < staffVoiceArrayCluster[voiceKey].length; i++) { // 如果该note是小节的第一个音, 那么之间把之前 过了 64 Unit beats 都累加上 if (staffVoiceArrayCluster[voiceKey][i].isGeometryFirstNoteOfMeasure) { let firstNoteBeatAccumulationBeforeCurrentMeasure = measureOnsetArray[staffVoiceArrayCluster[voiceKey][i].measureIndex] / Beats_.unit64Beats; beatsAccumulationOneSystem = firstNoteBeatAccumulationBeforeCurrentMeasure; // 每次开始一个voice list的时候, 都是从 0 开始并开始累计的 } // 如果该音不是和弦音, 就需要把之前的beats累加+ 目前这个beats 一起相加到一起 else if ( !staffVoiceArrayCluster[voiceKey][i].isChord && !staffVoiceArrayCluster[voiceKey][i].isGeometryFirstNoteOfMeasure ) { beatsAccumulationOneSystem = beatsAccumulationOneSystem + staffVoiceArrayCluster[voiceKey][i - 1].beats + staffVoiceArrayCluster[voiceKey][i - 1].beatsDot; } // 算出目前note的onset值 staffVoiceArrayCluster[voiceKey][i].onset = TheoryMath.keepDigitals( Beats_.unit64Beats * beatsAccumulationOneSystem, 3 ); staffVoiceArrayCluster[voiceKey][i].originalOnset = staffVoiceArrayCluster[voiceKey][i].onset; // 添加 Tie onset 信息 if (i !== 0 && staffVoiceArrayCluster[voiceKey][i].isTie) { this.processTieNoteOnset(staffVoiceArrayCluster[voiceKey][i], staffVoiceArrayCluster[voiceKey][i - 1]); } } } } } public static addGraceNoteOnset(noteXMLOrderList_: TheoryINote[]) { let minOnset = TheoryConstant.minOnset; for (let i = 0; i < noteXMLOrderList_.length; i++) { // 如果出现主音 if (noteXMLOrderList_[i].hasGraceGroup) { noteXMLOrderList_[i].graceGroupID = []; let graceMainNoteIndex = noteXMLOrderList_[i].id; let graceAccumulation = noteXMLOrderList_[i].graceAccumulation; if (graceAccumulation !== null) { for (let j = graceAccumulation; j >= 1; j--) { // main note 上记录 grace note 的 id noteXMLOrderList_[i].graceGroupID.push(i - j); // 把 grace note 的 onset 都赋值 noteXMLOrderList_[i - j].onset = noteXMLOrderList_[i].onset - j * TheoryConstant.graceNoteDuration; if (noteXMLOrderList_[i - j].onset < minOnset) { minOnset = noteXMLOrderList_[i - j].onset; } noteXMLOrderList_[i - j].graceMainNoteIndex = graceMainNoteIndex; } } } } /** * 如果minOnset 小于 0 就代表 grace note 里面有存在 负值的 onset 的 grace note * 那么根据 AI 要求 ,把那个 最小的 负值的 grace note 的 onset 变成 0; * 然后其他所有的音符都往后延长这个时长 * */ if (minOnset < 0) { // 如果 min onset 变为小于0了, 那么就要算出 距离 0 有多远, 然后每一个音符都要加上这个时值 let denotationTime = Math.abs(minOnset); for (let i = 0; i < noteXMLOrderList_.length; i++) { noteXMLOrderList_[i].onset = noteXMLOrderList_[i].onset + denotationTime; if (noteXMLOrderList_[i].hasOwnProperty("originalOnset")) { // 如果这个音有 originalOnset 的话 就要给他 加上 同样的时值 noteXMLOrderList_[i].originalOnset = noteXMLOrderList_[i].originalOnset + denotationTime; } } } } }