/// <summary> /// The divide. /// </summary> /// <param name="scoreTrack"> /// The score track. /// </param> /// <param name="paramPauseTreatment"> /// The param pause treatment. /// </param> /// <param name="paramEqualFM"> /// The param equal fm. /// </param> /// <returns> /// The <see cref="List{FmotivChain}"/>. /// </returns> public List<FmotivChain> Divide(ScoreTrack scoreTrack, ParamPauseTreatment paramPauseTreatment, ParamEqualFM paramEqualFM) { var chains = new List<FmotivChain>(); foreach (CongenericScoreTrack congenericTrack in scoreTrack.CongenericScoreTracks) { var fmotivChain = (FmotivChain)Divide(congenericTrack, paramPauseTreatment, paramEqualFM).Clone(); fmotivChain.Id = chains.Count; chains.Add(fmotivChain); } return chains; }
/// <summary> /// The divide. /// </summary> /// <param name="congenericTrack"> /// The congeneric track. /// </param> /// <param name="paramPauseTreatment"> /// The param pause treatment. /// параметр как учитывать паузу : /// игнорировать, звуковой след предыдущего звука, вырожденныый звук /// </param> /// <param name="paramEqualFM"> /// The param equal fm. /// как сравнивать ф-мотивы с секвентым переносом, либо нет /// </param> /// <returns> /// The <see cref="FmotivChain"/>. /// </returns> public FmotivChain Divide(CongenericScoreTrack congenericTrack, ParamPauseTreatment paramPauseTreatment, ParamEqualFM paramEqualFM) { // сохраняем имя цепи фмотивов как имя монотрека var priorityDiscover = new PriorityDiscover(); var fmotivDivider = new FmotivDivider(); var fmotivIdentifier = new FmotivIdentifier(); // подсчет приоритетов priorityDiscover.Calculate(congenericTrack); // разбиение FmotivChain chain = fmotivDivider.GetDivision(congenericTrack, paramPauseTreatment); // нахождение одинаковых return fmotivIdentifier.GetIdentification(chain, paramPauseTreatment, paramEqualFM); }
/// <summary> /// The get identification. /// </summary> /// <param name="fmotivChain"> /// The fmotiv chain. /// </param> /// <param name="paramPauseTreatment"> /// The param pause treatment. /// </param> /// <param name="paramEqualFM"> /// The param equal fm. /// </param> /// <returns> /// The <see cref="FmotivChain"/>. /// </returns> public FmotivChain GetIdentification(FmotivChain fmotivChain, ParamPauseTreatment paramPauseTreatment, ParamEqualFM paramEqualFM) { var chain = (FmotivChain)fmotivChain.Clone(); for (int i = 0; i < chain.FmotivList.Count; i++) { for (int j = i; j < chain.FmotivList.Count; j++) { if (chain.FmotivList[i].FmEquals(chain.FmotivList[j], paramPauseTreatment, paramEqualFM)) { chain.FmotivList[j].Id = chain.FmotivList[i].Id; } } } for (int i = 0; i < chain.FmotivList.Max(fl => fl.Id); i++) { bool haveId = chain.FmotivList.Any(t => t.Id == i); // флаг того что есть такой id в цепочке if (!haveId) { foreach (Fmotiv fmotiv in chain.FmotivList) { if (fmotiv.Id > i) { // уменьшаем на 1 id тех фмотивов которые больше текущей id - i, которой не нашлось в цепи fmotiv.Id--; } } // уменьшаем i на 1 чтобы еще раз проверить есть ли это i среди цепи после уменьшения id-ек больших i i--; } } return chain; }
/// <summary> /// The fm equals. /// </summary> /// <param name="obj"> /// The object. /// </param> /// <param name="paramPauseTreatment"> /// The param pause treatment. /// </param> /// <param name="paramEqualFM"> /// The param equal fm. /// </param> /// <returns> /// The <see cref="bool"/>. /// </returns> /// <exception cref="Exception"> /// Thrown if paramEqualFM is unknown. /// </exception> public bool FmEquals(object obj, ParamPauseTreatment paramPauseTreatment, ParamEqualFM paramEqualFM) { // для сравнения паузы не нужны, поэтому сравнивае ф-мотивы без пауз (они игнорируются, но входят в состав ф-мотива) Fmotiv self = PauseTreatment(paramPauseTreatment).TieGathered(); Fmotiv other = ((Fmotiv)obj).PauseTreatment(paramPauseTreatment).TieGathered(); int modulation = 0; bool firstTime = true; if (self.NoteList.Count != other.NoteList.Count) { // фмотивы - неодинаковы, так как входит разное количество нот return false; } for (int i = 0; i < self.NoteList.Count; i++) { // одинаково ли количество высот у нот? if (self.NoteList[i].Pitch.Count != other.NoteList[i].Pitch.Count) { // если нет - фмотивы - неодинаковы return false; } // одинаковы ли длительности у нот? if (!self.NoteList[i].Duration.Equals(other.NoteList[i].Duration)) { // если нет - фмотивы - неодинаковы return false; } if ((self.NoteList[i].Pitch.Count == 0) || (other.NoteList[i].Pitch.Count == 0)) { if (!((self.NoteList[i].Pitch.Count == 0) && (other.NoteList[i].Pitch.Count == 0))) { // если одна из нот пауза, а вторая - нет, то ф-мотивы не одинаковы return false; } // если две паузы одно длительности то идем дальше. пропуская их (считаем что это две одинаковые ноты в любом случае) } else { // если две ноты - не паузы // в зависимости от параметра учета секвентного переноса switch (paramEqualFM) { case ParamEqualFM.Sequent: // учитывая секентный перенос (Sequent) for (int j = 0; j < self.NoteList[i].Pitch.Count; j++) { if (firstTime) { // при первом сравнении вычисляем на сколько полутонов отличаются первые ноты, // последущие должны отличаться на столько же, чтобы фмотивы были равны modulation = self.NoteList[i].Pitch[j].MidiNumber - other.NoteList[i].Pitch[j].MidiNumber; firstTime = false; } // одинаковы ли при этом высоты / правильно ли присутствует секвентный перенос (модуляция) if (modulation != (self.NoteList[i].Pitch[j].MidiNumber - other.NoteList[i].Pitch[j].MidiNumber)) { return false; } } break; case ParamEqualFM.NonSequent: // без секвентного переноса (NonSequent) for (int j = 0; j < self.NoteList[i].Pitch.Count; j++) { if (self.NoteList[i].Pitch[j].MidiNumber != other.NoteList[i].Pitch[j].MidiNumber) { return false; } } break; default: throw new Exception("Error Fmotiv.ParamEqualFM parameter contains wrong value!"); } } } return true; }