/// <summary> /// ACHTUNG: This function is deprecated!! Use the other AdjustVelocitiesHairpin(...). /// First creates a hairpin in the velocities from beginIndex to endIndex (non-inclusive), /// then adjusts all the remaining velocities in this VoiceDef by the finalFactor. /// endIndex must be greater than beginIndex + 1. /// The factors by which the velocities are multiplied change arithmetically: The velocities /// at beginIndex are multiplied by 1.0, and the velocities from endIndex to the end of the /// VoiceDef by finalFactor. /// Can be used to create a diminuendo or crescendo. /// </summary> /// <param name="beginDimIndex"></param> /// <param name="endDimIndex"></param> /// <param name="p"></param> public void AdjustVelocitiesHairpin(int beginIndex, int endIndex, double finalFactor) { Debug.Assert(((beginIndex + 1) < endIndex) && (finalFactor >= 0) && (endIndex <= Count)); int nNonMidiChordDefs = GetNumberOfNonMidiOrInputChordDefs(beginIndex, endIndex); double factorIncrement = (finalFactor - 1.0) / (endIndex - beginIndex - nNonMidiChordDefs); double factor = 1.0; for (int i = beginIndex; i < endIndex; ++i) { MidiChordDef iumdd = _uniqueDefs[i] as MidiChordDef; if (iumdd != null) { iumdd.AdjustVelocities(factor); factor += factorIncrement; } } for (int i = endIndex; i < _uniqueDefs.Count; ++i) { MidiChordDef iumdd = _uniqueDefs[i] as MidiChordDef; if (iumdd != null) { iumdd.AdjustVelocities(factor); } } }
/// <summary> /// Stretch or compress all the durations in the list to fit the given total duration. /// This does not change the VoiceDef's MsPosition, but does affect its EndMsPosition. /// </summary> /// <param name="msDuration"></param> public void SetMsDuration(int msDuration) { Debug.Assert(msDuration > 0); List <int> relativeDurations = new List <int>(); foreach (IUniqueDef iumdd in _uniqueDefs) { if (iumdd.MsDuration > 0) { relativeDurations.Add(iumdd.MsDuration); } } List <int> newDurations = MidiChordDef.GetIntDurations(msDuration, relativeDurations, relativeDurations.Count); Debug.Assert(newDurations.Count == relativeDurations.Count); int i = 0; int newTotal = 0; foreach (IUniqueDef iumdd in _uniqueDefs) { if (iumdd.MsDuration > 0) { iumdd.MsDuration = newDurations[i]; newTotal += iumdd.MsDuration; ++i; } } Debug.Assert(msDuration == newTotal); SetMsPositions(); }
/// <summary> /// Creates a moving pan from startPanValue at startMsPosition to endPanValue at endMsPosition. /// Implemented using one pan value per MidiChordDef. /// This function does NOT change pan values outside the position range given in its arguments. /// </summary> public void SetPanGliss(int startMsPosition, int endMsPosition, int startPanValue, int endPanValue) { int beginIndex = FindIndexAtMsPosition(startMsPosition); int endIndex = FindIndexAtMsPosition(endMsPosition); Debug.Assert(((beginIndex + 1) < endIndex) && (startPanValue >= 0) && (startPanValue <= 127) && (endPanValue >= 0) && (endPanValue <= 127) && (endIndex <= Count)); int nNonMidiChordDefs = GetNumberOfNonMidiOrInputChordDefs(beginIndex, endIndex); double increment = ((double)(endPanValue - startPanValue)) / (endIndex - beginIndex - nNonMidiChordDefs); int panValue = startPanValue; List <IUniqueDef> lmdds = _uniqueDefs; for (int i = beginIndex; i < endIndex; ++i) { MidiChordDef iumdd = _uniqueDefs[i] as MidiChordDef; if (iumdd != null) { iumdd.PanMsbs = new List <byte>() { (byte)panValue }; panValue += (int)increment; } } }
/// <summary> /// Creates a new TrkDef containing just the argument midiChordDef, /// then calls the other InsertInRest() function with the voiceDef as argument. /// </summary> public void InsertInRest(MidiChordDef midiChordDef) { List <IUniqueDef> iuds = new List <IUniqueDef>() { midiChordDef }; TrkDef trkDefToInsert = new TrkDef(this.MidiChannel, iuds); InsertInRest(trkDefToInsert); }
/// <summary> /// Multiplies each velocity value in the MidiChordDefs /// from beginIndex to (not including) endIndex by the argument factor. /// </summary> public void AdjustVelocities(int beginIndex, int endIndex, double factor) { CheckIndices(beginIndex, endIndex); for (int i = beginIndex; i < endIndex; ++i) { MidiChordDef iumdd = _uniqueDefs[i] as MidiChordDef; if (iumdd != null) { iumdd.AdjustVelocities(factor); } } }
/// <summary> /// Sets the pitchwheelDeviation for MidichordDefs in the range beginIndex to (not including) endindex. /// Rests in the range dont change. /// </summary> public void SetPitchWheelDeviation(int beginIndex, int endIndex, int deviation) { CheckIndices(beginIndex, endIndex); for (int i = beginIndex; i < endIndex; ++i) { MidiChordDef mcd = this[i] as MidiChordDef; if (mcd != null) { mcd.PitchWheelDeviation = M.MidiValue(deviation); } } }
/// <summary> /// Grp objects own unique IUniqueDefs, but can share Gamuts. The Gamut may not be null. /// </summary> /// <param name="gamut">can not be null</param> /// <param name="rootOctave">must be greater than or equal to 0</param> /// <param name="nPitchesPerChord">must be greater than 0</param> /// <param name="msDurationPerChord">must be greater than 0</param> /// <param name="nChords">must be greater than 0</param> /// <param name="velocityFactor">must be greater than 0.0</param> public Grp(Gamut gamut, int rootOctave, int nPitchesPerChord, int msDurationPerChord, int nChords, double velocityFactor) : base(0, 0, new List<IUniqueDef>()) { Debug.Assert(gamut != null); Debug.Assert(rootOctave >= 0); Debug.Assert(nPitchesPerChord > 0); Debug.Assert(msDurationPerChord > 0); Debug.Assert(nChords > 0); Debug.Assert(velocityFactor > 0.0); _gamut = gamut; for(int i = 0; i < nChords; ++i) { int rootNotatedPitch; if(i == 0) { rootNotatedPitch = gamut.AbsolutePitchHierarchy[i] + (12 * rootOctave); rootNotatedPitch = (rootNotatedPitch <= gamut.MaxPitch) ? rootNotatedPitch : gamut.MaxPitch; } else { List<byte> previousPitches = ((MidiChordDef)_uniqueDefs[i - 1]).BasicMidiChordDefs[0].Pitches; if(previousPitches.Count > 1) { rootNotatedPitch = previousPitches[1]; } else { rootNotatedPitch = gamut.AbsolutePitchHierarchy[i]; while(rootNotatedPitch < previousPitches[0]) { rootNotatedPitch += 12; if(rootNotatedPitch > gamut.MaxPitch) { rootNotatedPitch = gamut.MaxPitch; break; } } } } MidiChordDef mcd = new MidiChordDef(msDurationPerChord, gamut, rootNotatedPitch, nPitchesPerChord, null); mcd.AdjustVelocities(velocityFactor); _uniqueDefs.Add(mcd); } SetBeamEnd(); }
public MidiChord(int channel, MidiChordDef midiChordDef, OutputDevice midiOutputDevice) : base(channel, 0, midiChordDef.MsDuration) { _midiOutputDevice = midiOutputDevice; List<BasicMidiChordDef> basicMidiChordDefs = midiChordDef.BasicMidiChordDefs; Debug.Assert(basicMidiChordDefs.Count > 0); List<int> realBasicMidiChordDurations = MidiChordDef.GetIntDurations(MsDuration, midiChordDef.BasicChordDurations, basicMidiChordDefs.Count); var notesToStop = new SortedSet<byte>(); int i = 0; foreach(BasicMidiChordDef basicMidiChordDef in midiChordDef.BasicMidiChordDefs) { this._basicMidiChords.Add(new BasicMidiChord(channel, this, basicMidiChordDef, realBasicMidiChordDurations[i++])); if(basicMidiChordDef.HasChordOff) { foreach(byte note in basicMidiChordDef.Pitches) { if(!notesToStop.Contains(note)) notesToStop.Add(note); } } } if(midiChordDef.Bank != null) { _bank = new BankControl(channel, (byte)midiChordDef.Bank); } if(midiChordDef.Patch != null) { _patch = new PatchControl(channel, (byte)midiChordDef.Patch); } // Moritz currently never repeats MidiChords, so the _repeat field is unnecessary. // However: the value of midiChordDef.Repeat is saved in SVG-MIDI files, // and may be used by the web AssistantPerformer. //_repeat = midiChordDef.Repeat; if(midiChordDef.PitchWheelDeviation != null) { _pitchWheelDeviation = new PitchWheelDeviation(channel, (byte)midiChordDef.PitchWheelDeviation); } if(midiChordDef.MidiChordSliderDefs != null) CreateSliders(channel, midiChordDef.MidiChordSliderDefs, MsDuration); SetMessagesDict(); }
/// <summary> /// Removes the pitchwheel commands (not the pitchwheelDeviations) /// from chords in the range beginIndex to (not including) endIndex. /// Rests in the range are not changed. /// </summary> public void RemoveScorePitchWheelCommands(int beginIndex, int endIndex) { CheckIndices(beginIndex, endIndex); for (int i = beginIndex; i < endIndex; ++i) { MidiChordDef iumdd = this[i] as MidiChordDef; if (iumdd != null) { MidiChordDef umcd = iumdd as MidiChordDef; if (umcd != null) { umcd.MidiChordSliderDefs.PitchWheelMsbs = new List <byte>(); } } } }
public override IUniqueDef DeepClone() { MidiChordDef rval = new MidiChordDef(); rval.MsPosition = this.MsPosition; // rval.MsDuration must be set after setting BasicMidiChordDefs See below. rval.Bank = this.Bank; rval.Patch = this.Patch; rval.PitchWheelDeviation = this.PitchWheelDeviation; rval.HasChordOff = this.HasChordOff; rval.Lyric = this.Lyric; rval.MinimumBasicMidiChordMsDuration = this.MinimumBasicMidiChordMsDuration; // required when changing a midiChord's duration rval.NotatedMidiPitches = new List <byte>(this.NotatedMidiPitches); // the displayed noteheads // rval.MidiVelocity must be set after setting BasicMidiChordDefs See below. rval.OrnamentNumberSymbol = this.OrnamentNumberSymbol; // the displayed ornament number MidiChordSliderDefs m = this.MidiChordSliderDefs; List <byte> pitchWheelMsbs = NewListByteOrNull(m.PitchWheelMsbs); List <byte> panMsbs = NewListByteOrNull(m.PanMsbs); List <byte> modulationWheelMsbs = NewListByteOrNull(m.ModulationWheelMsbs); List <byte> expressionMsbs = NewListByteOrNull(m.ExpressionMsbs); if (pitchWheelMsbs != null || panMsbs != null || modulationWheelMsbs != null || expressionMsbs != null) { rval.MidiChordSliderDefs = new MidiChordSliderDefs(pitchWheelMsbs, panMsbs, modulationWheelMsbs, expressionMsbs); } else { rval.MidiChordSliderDefs = null; } List <BasicMidiChordDef> newBs = new List <BasicMidiChordDef>(); foreach (BasicMidiChordDef b in this.BasicMidiChordDefs) { List <byte> pitches = new List <byte>(b.Pitches); List <byte> velocities = new List <byte>(b.Velocities); newBs.Add(new BasicMidiChordDef(b.MsDuration, b.BankIndex, b.PatchIndex, b.HasChordOff, pitches, velocities)); } rval.BasicMidiChordDefs = newBs; rval.MsDuration = this.MsDuration; rval.MidiVelocity = this.MidiVelocity; // needed for displaying dynamics (must be set *after* setting BasicMidiChordDefs) return(rval); }
/// <summary> /// Creates an exponential change (per index) of pitchwheelDeviation from startMsPosition to endMsPosition, /// </summary> /// <param name="finale"></param> protected void AdjustPitchWheelDeviations(int startMsPosition, int endMsPosition, int startPwd, int endPwd) { double furies1StartPwdValue = startPwd, furies1EndPwdValue = endPwd; int beginIndex = FindIndexAtMsPosition(startMsPosition); int endIndex = FindIndexAtMsPosition(endMsPosition); int nNonMidiChordDefs = GetNumberOfNonMidiOrInputChordDefs(beginIndex, endIndex); double pwdfactor = Math.Pow(furies1EndPwdValue / furies1StartPwdValue, (double)1 / (endIndex - beginIndex - nNonMidiChordDefs)); // f13.Count'th root of furies1EndPwdValue/furies1StartPwdValue -- the last pwd should be furies1EndPwdValue for (int i = beginIndex; i < endIndex; ++i) { MidiChordDef umc = _uniqueDefs[i] as MidiChordDef; if (umc != null) { umc.PitchWheelDeviation = M.MidiValue((int)(furies1StartPwdValue * (Math.Pow(pwdfactor, i)))); } } }
/// <summary> /// From startMsPosition to (not including) endMsPosition, /// replace all MidiChordDefs or InputChordDefs by UniqueMidiRestDefs, then aglommerate the rests. /// </summary> public void Erase(int startMsPosition, int endMsPosition) { int beginIndex = FindIndexAtMsPosition(startMsPosition); int endIndex = FindIndexAtMsPosition(endMsPosition); for (int i = beginIndex; i < endIndex; ++i) { MidiChordDef mcd = this[i] as MidiChordDef; InputChordDef icd = this[i] as InputChordDef; IUniqueDef iud = (mcd == null) ? (IUniqueDef)icd : (IUniqueDef)mcd; if (iud != null) { RestDef umrd = new RestDef(iud.MsPosition, iud.MsDuration); RemoveAt(i); Insert(i, umrd); } } AgglomerateRests(); }
public OutputChordSymbol(Voice voice, MidiChordDef umcd, int minimumCrotchetDurationMS, float fontSize) : base(voice, umcd.MsDuration, umcd.MsPosition, minimumCrotchetDurationMS, fontSize) { _midiChordDef = umcd; _msDurationToNextBarline = umcd.MsDurationToNextBarline; SetNoteheadPitches(umcd.NotatedMidiPitches); if(umcd.OrnamentNumberSymbol != 0) { OrnamentText ornamentText = new OrnamentText(this, "~" + umcd.OrnamentNumberSymbol.ToString(), FontHeight); DrawObjects.Add(ornamentText); } if(umcd.Lyric != null) { LyricText lyric = new LyricText(this, umcd.Lyric, FontHeight); DrawObjects.Add(lyric); } }
/// <summary> /// Transposes the UniqueDefs from the beginIndex upto (but not including) endIndex /// by an equally increasing amount, so that the final MidiChordDef or InputChordDef is transposed by glissInterval. /// beginIndex must be less than endIndex. /// glissInterval can be negative. /// </summary> public void StepwiseGliss(int beginIndex, int endIndex, int glissInterval) { CheckIndices(beginIndex, endIndex); Debug.Assert(beginIndex < endIndex); int nNonMidiChordDefs = GetNumberOfNonMidiOrInputChordDefs(beginIndex, endIndex); int nSteps = (endIndex - beginIndex - nNonMidiChordDefs); double interval = ((double)glissInterval) / nSteps; double step = interval; for (int i = beginIndex; i < endIndex; ++i) { MidiChordDef mcd = _uniqueDefs[i] as MidiChordDef; InputChordDef icd = _uniqueDefs[i] as InputChordDef; IUniqueChordDef iucd = (mcd == null) ? (IUniqueChordDef)icd : (IUniqueChordDef)mcd; if (iucd != null) { iucd.Transpose((int)Math.Round(interval)); interval += step; } } }
/// Creates a hairpin in the velocities from startMsPosition to endMsPosition (non-inclusive). /// This function does NOT change velocities outside the range given in its arguments. /// There must be at least two IUniqueMidiDurationDefs in the msPosition range given in the arguments. /// The factors by which the velocities are multiplied change arithmetically: /// The velocity of the first IUniqueMidiDurationDefs is multiplied by startFactor, and the velocity /// of the last MidiChordDef in range by endFactor. /// Can be used to create a diminueno or crescendo. public void AdjustVelocitiesHairpin(int startMsPosition, int endMsPosition, double startFactor, double endFactor) { int beginIndex = FindIndexAtMsPosition(startMsPosition); int endIndex = FindIndexAtMsPosition(endMsPosition); Debug.Assert(((beginIndex + 1) < endIndex) && (startFactor >= 0) && (endFactor >= 0) && (endIndex <= Count)); int nNonMidiChordDefs = GetNumberOfNonMidiOrInputChordDefs(beginIndex, endIndex); double factorIncrement = (endFactor - startFactor) / (endIndex - beginIndex - nNonMidiChordDefs); double factor = startFactor; List <IUniqueDef> lmdds = _uniqueDefs; for (int i = beginIndex; i < endIndex; ++i) { MidiChordDef iumdd = _uniqueDefs[i] as MidiChordDef; if (iumdd != null) { iumdd.AdjustVelocities(factor); factor += factorIncrement; } } }
private List<IUniqueDef> GetMidiChordDefs(List<int> pitches, List<int> durations) { Debug.Assert(pitches.Count == 96); Debug.Assert(durations.Count == 96); const int durationFactor = 48; // the shortest note is 48ms List<IUniqueDef> defs = new List<IUniqueDef>(); List<byte> velocities = new List<byte>() { (byte)127 }; int msPosition = 0; for(int i = 0; i < 96; ++i) { List<byte> pitchesArg = new List<byte>() { (byte)pitches[i] }; int msDuration = durations[i] * durationFactor; MidiChordDef midiChordDef = new MidiChordDef(pitchesArg, velocities, msDuration, true); midiChordDef.MsPositionReFirstUD = msPosition; defs.Add(midiChordDef); msPosition += msDuration; } return defs; }
private IUniqueDef GetMidiChordDef(List<byte> chordIntervals, byte chordVelocity, int chordDuration, int relativePitch, int msPosition) { List<byte> pitches = GetPitches(relativePitch, chordIntervals); List<byte> velocities = GetVelocities(chordVelocity, chordIntervals.Count() + 1); IUniqueDef mcd = new MidiChordDef(pitches, velocities, chordDuration, true); mcd.MsPositionReFirstUD = msPosition; return mcd; }
/// <summary> /// Returns true if the gamut.List contains all the pitches in the argument. Otherwise false. /// </summary> public bool ContainsAllPitches(MidiChordDef mcd) { foreach(BasicMidiChordDef bmcd in mcd.BasicMidiChordDefs) { for(int i = 0; i < bmcd.Pitches.Count; ++i) { if(this.Contains(bmcd.Pitches[i]) == false) { return false; } } } return true; }
public override IUniqueDef DeepClone() { MidiChordDef rval = new MidiChordDef(); rval.MsPosition = this.MsPosition; // rval.MsDuration must be set after setting BasicMidiChordDefs See below. rval.Bank = this.Bank; rval.Patch = this.Patch; rval.PitchWheelDeviation = this.PitchWheelDeviation; rval.HasChordOff = this.HasChordOff; rval.Lyric = this.Lyric; rval.MinimumBasicMidiChordMsDuration = this.MinimumBasicMidiChordMsDuration; // required when changing a midiChord's duration rval.NotatedMidiPitches = new List<byte>(this.NotatedMidiPitches); // the displayed noteheads // rval.MidiVelocity must be set after setting BasicMidiChordDefs See below. rval.OrnamentNumberSymbol = this.OrnamentNumberSymbol; // the displayed ornament number MidiChordSliderDefs m = this.MidiChordSliderDefs; List<byte> pitchWheelMsbs = NewListByteOrNull(m.PitchWheelMsbs); List<byte> panMsbs = NewListByteOrNull(m.PanMsbs); List<byte> modulationWheelMsbs = NewListByteOrNull(m.ModulationWheelMsbs); List<byte> expressionMsbs = NewListByteOrNull(m.ExpressionMsbs); if(pitchWheelMsbs != null || panMsbs != null || modulationWheelMsbs != null || expressionMsbs != null) rval.MidiChordSliderDefs = new MidiChordSliderDefs(pitchWheelMsbs, panMsbs, modulationWheelMsbs, expressionMsbs); else rval.MidiChordSliderDefs = null; List<BasicMidiChordDef> newBs = new List<BasicMidiChordDef>(); foreach(BasicMidiChordDef b in this.BasicMidiChordDefs) { List<byte> pitches = new List<byte>(b.Pitches); List<byte> velocities = new List<byte>(b.Velocities); newBs.Add(new BasicMidiChordDef(b.MsDuration, b.BankIndex, b.PatchIndex, b.HasChordOff, pitches, velocities)); } rval.BasicMidiChordDefs = newBs; rval.MsDuration = this.MsDuration; rval.MidiVelocity = this.MidiVelocity; // needed for displaying dynamics (must be set *after* setting BasicMidiChordDefs) return rval; }
/// <summary> /// Returns either a new RestDef or a new MidiChordDef /// In both cases, MsPosition is set to zero, Lyric is set to null. /// </summary> private DurationDef GetDurationDef(int index) { DurationDef rval = null; BasicChordMidiSettings bcms = _basicChordMidiSettings; if(bcms.MidiPitches[index].Count == 0) { /// RestDefs are immutable, and have no MsPosition property. /// UniqueRestDefs are mutable RestDefs with both MsPositon and MsDuration properties. int restMsDuration = bcms.Durations[index]; rval = new RestDef(0, restMsDuration); } else { /// Create a new MidiChordDef (with msPosition=0, lyric=null) bool hasChordOff = BoolOrDefaultValue(bcms.ChordOffs, index, M.DefaultHasChordOff); // true int duration = bcms.Durations[index]; List<byte> rootMidiPitches = bcms.MidiPitches[index]; List<byte> rootMidiVelocities = bcms.Velocities[index]; byte? bankIndex = ByteOrNull(_bankIndices, index); byte? patchIndex = ByteOrNull(_patchIndices, index); byte pitchwheelDeviation = ByteOrDefaultValue(_pitchwheelDeviations, index, M.DefaultPitchWheelDeviation); // 2 List<byte> pitchwheelEnvelope = ListByte(_pitchwheelEnvelopes, index); List<byte> panEnvelope = ListByte(_panEnvelopes, index); List<byte> modulationWheelEnvelope = ListByte(_modulationWheelEnvelopes, index); List<byte> expressionEnvelope = ListByte(_expressionEnvelopes, index); MidiChordSliderDefs midiChordSliderDefs = new MidiChordSliderDefs(pitchwheelEnvelope, panEnvelope, modulationWheelEnvelope, expressionEnvelope); OrnamentSettings os = _ornamentSettings; List<BasicMidiChordDef> basicMidiChordDefs = new List<BasicMidiChordDef>(); int ornamentNumber; if(os == null || _ornamentNumbers[index] == 0) { ornamentNumber = 0; BasicMidiChordDef bmcd = new BasicMidiChordDef(duration, bankIndex, patchIndex, hasChordOff, rootMidiPitches, rootMidiVelocities); basicMidiChordDefs.Add(bmcd); } else { ornamentNumber = _ornamentNumbers[index]; int ornamentMinMsDuration = IntOrDefaultValue(_ornamentMinMsDurations, index, M.DefaultOrnamentMinimumDuration); // 1 List<int> ornamentValues = os.OrnamentValues[_ornamentNumbers[index] - 1]; for(int i = 0; i < ornamentValues.Count; ++i) { int oIndex = ornamentValues[i] - 1; bool oHasChordOff = BoolOrDefaultValue(os.BasicChordMidiSettings.ChordOffs, oIndex, M.DefaultHasChordOff); int oDuration = os.BasicChordMidiSettings.Durations[oIndex]; List<byte> oMidiPitches = os.BasicChordMidiSettings.MidiPitches[oIndex]; List<byte> oVelocities = os.BasicChordMidiSettings.Velocities[oIndex]; byte? oBank = ByteOrNull(os.BankIndices, oIndex); byte? oPatch = ByteOrNull(os.PatchIndices, oIndex); BasicMidiChordDef bmcd = new BasicMidiChordDef(oDuration, oBank, oPatch, oHasChordOff, oMidiPitches, oVelocities); basicMidiChordDefs.Add(bmcd); } // The basicMidiChordDefs currently contain the values from the ornaments form. // All oBank and oPatch values will be null if the corresponding field in the ornament form was empty. // The durations, pitches and velocities are relative to the main palette's values. RemoveDuplicateBankAndPatchValues(basicMidiChordDefs); if(basicMidiChordDefs[0].BankIndex == null) basicMidiChordDefs[0].BankIndex = bankIndex; // can be null if(basicMidiChordDefs[0].PatchIndex == null) basicMidiChordDefs[0].PatchIndex = patchIndex; Debug.Assert(basicMidiChordDefs[0].PatchIndex != null); basicMidiChordDefs = Moritz.Spec.MidiChordDef.FitToDuration(basicMidiChordDefs, duration, ornamentMinMsDuration); foreach(BasicMidiChordDef b in basicMidiChordDefs) { List<byte> combinedPitches = new List<byte>(); foreach(byte pitch in b.Pitches) { foreach(byte rootMidiPitch in rootMidiPitches) { combinedPitches.Add(M.MidiValue(rootMidiPitch + pitch)); } } b.Pitches = combinedPitches; List<byte> combinedVelocities = new List<byte>(); foreach(byte velocity in b.Velocities) { foreach(byte rootMidiVelocity in rootMidiVelocities) { combinedVelocities.Add(M.MidiValue(rootMidiVelocity + velocity)); } } b.Velocities = combinedVelocities; } } rval = new MidiChordDef( duration, pitchwheelDeviation, hasChordOff, rootMidiPitches, rootMidiVelocities, ornamentNumber, midiChordSliderDefs, basicMidiChordDefs); } return rval; }
/// <summary> /// Sets _momentDefsListPerVerse to contain a list of MomentDefs for each verse. /// Each MomentDef is positioned with respect to the beginning of its verse, and contains /// a single MidiChordDef in its MidiChordDefs list. /// </summary> private void SetMomentDefsListPerVerse() { _momentDefsListPerVerse = new List<List<MomentDef>>(); List<List<int>> momentDefMsWidthPerVerse = MomentDefMsWidthPerVerse; List<List<int>> midiChordDefMsDurPerVerse = MidiChordDefMsDurationsPerVerse; CheckWidths(momentDefMsWidthPerVerse, midiChordDefMsDurPerVerse); List<List<string>> lyricsPerVerse = LyricsPerVerse; List<byte> verseVelocities = new List<byte>() { (byte)64, (byte)75, (byte)90, (byte)105, (byte)120 }; for(int verseIndex = 0; verseIndex < 5; ++verseIndex) { int momentMsPos = 0; List<int> momentMsWidth = momentDefMsWidthPerVerse[verseIndex]; List<int> midiChordMsDur = midiChordDefMsDurPerVerse[verseIndex]; List<string> lyrics = lyricsPerVerse[verseIndex]; List<MomentDef> momentDefs = new List<MomentDef>(); _momentDefsListPerVerse.Add(momentDefs); byte patch = (byte)(123 + verseIndex); // top 5 patches in bank 0 List<byte> velocity = new List<byte>() { verseVelocities[verseIndex] }; for(int syllableIndex = 0; syllableIndex < momentMsWidth.Count; ++syllableIndex) { Debug.Assert(midiChordMsDur[syllableIndex] <= momentMsWidth[syllableIndex]); MomentDef momentDef = new MomentDef(momentMsPos); momentDef.MsWidth = momentMsWidth[syllableIndex]; momentDefs.Add(momentDef); List<byte> pitch = new List<byte>() { (byte)syllableIndex }; // the syllables are organised like this in the soundfont. int msDuration = midiChordMsDur[syllableIndex]; #region MidiChordDef lmcd = new MidiChordDef(); lmcd.HasChordOff = true; // Bank, and Patch are added to *every* chord so that performances can start anywhere. // If the Assistant Performer is clever enough, repeated controls are not actually sent. lmcd.Bank = (byte)(0); lmcd.Patch = patch; lmcd.Lyric = lyrics[syllableIndex]; // the following determine what is actually heard List<byte> expressionMsbs = new List<byte>() { (byte)65 }; lmcd.MidiChordSliderDefs = new MidiChordSliderDefs(null, null, null, expressionMsbs); lmcd.BasicMidiChordDefs.Add(new BasicMidiChordDef(msDuration, 0, patch, true, pitch, velocity)); lmcd.MsDuration = msDuration; // these two attributes determine the symbols in the score. lmcd.NotatedMidiPitches = new List<byte>() { 67 }; // display middle G, even though "pitch" is different. lmcd.MidiVelocity = velocity[0]; // determines the visible dynamic symbol #endregion momentDef.MidiChordDefs.Add(lmcd); momentMsPos += momentDef.MsWidth; } } }
/// <summary> /// Returns a new MidiChordDef having msDuration, whose BasicMidiChordDefs are created from the MidiChordDefs and RestDefs in the Trk. /// BasicMidiChordDefs created from MidiChordDefs are the MidiChordDef's BasicMidiChordDef[0]. /// BasicMidiChordDefs created from RestDefs have a single pitch (=0) and velocity=0. /// The durations of the returned BasicMidiChordDefs are in proportion to the durations of the MidiChordDefs and RestDefs in the Trk. /// The Trk (which must contain at least one MidiChordDef) is not changed by calling this function. /// </summary> /// <param name="msDuration">The duration of the returned MidiChordDef</param> public MidiChordDef ToMidiChordDef(int msDuration) { List<BasicMidiChordDef> basicMidiChordDefs = new List<BasicMidiChordDef>(); int bmcMsDuration = 0; byte? bmcBank = null; byte? bmcPatch = null; bool bmcHasChordOff = true; List<byte> restPitch = new List<byte>() { 0 }; List<byte> restVelocity = new List<byte>() { 0 }; List<byte> bmcPitches = null; List<byte> bmcVelocities = null; int totalDuration = 0; int nMidiChordDefs = 0; foreach(IUniqueDef iud in UniqueDefs) { MidiChordDef mcd = iud as MidiChordDef; RestDef restDef = iud as RestDef; if(mcd != null) { bmcBank = mcd.BasicMidiChordDefs[0].BankIndex; bmcPatch = mcd.BasicMidiChordDefs[0].PatchIndex; bmcHasChordOff = mcd.BasicMidiChordDefs[0].HasChordOff; bmcPitches = mcd.BasicMidiChordDefs[0].Pitches; bmcVelocities = mcd.BasicMidiChordDefs[0].Velocities; bmcMsDuration = mcd.MsDuration; nMidiChordDefs++; } else if(restDef != null) { bmcBank = null; bmcPatch = null; bmcHasChordOff = false; bmcPitches = restPitch; bmcVelocities = restVelocity; bmcMsDuration = restDef.MsDuration; } if(iud is DurationDef) { var basicMidiChordDef = new BasicMidiChordDef(bmcMsDuration, bmcBank, bmcPatch, bmcHasChordOff, bmcPitches, bmcVelocities); totalDuration += bmcMsDuration; basicMidiChordDefs.Add(basicMidiChordDef); } } Debug.Assert(nMidiChordDefs > 0, "Error: The original Trk must contain at least one MidiChordDef."); const byte pitchWheelDeviation = 2; const bool hasChordOff = true; const MidiChordSliderDefs midiChordSliderDefs = null; List<byte> rootMidiPitches = new List<byte>(basicMidiChordDefs[0].Pitches); List<byte> rootMidiVelocities = new List<byte>(basicMidiChordDefs[0].Velocities); MidiChordDef returnMCD = new MidiChordDef(totalDuration, pitchWheelDeviation, hasChordOff, rootMidiPitches, rootMidiVelocities, nMidiChordDefs, midiChordSliderDefs, basicMidiChordDefs); returnMCD.MsDuration = msDuration; return returnMCD; }
/// <summary> /// A deep clone! /// </summary> /// <returns></returns> public override object Clone() { MidiChordDef rval = new MidiChordDef(); rval.MsPositionReFirstUD = this.MsPositionReFirstUD; // rval.MsDuration must be set after setting BasicMidiChordDefs See below. rval.Bank = this.Bank; rval.Patch = this.Patch; rval.PitchWheelDeviation = this.PitchWheelDeviation; rval.HasChordOff = this.HasChordOff; rval.BeamContinues = this.BeamContinues; rval.Lyric = this.Lyric; rval.MinimumBasicMidiChordMsDuration = MinimumBasicMidiChordMsDuration; // required when changing a midiChord's duration rval.NotatedMidiPitches = _notatedMidiPitches; // a clone of the displayed notehead pitches rval.NotatedMidiVelocities = _notatedMidiVelocities; // a clone of the displayed notehead velocities // rval.MidiVelocity must be set after setting BasicMidiChordDefs See below. rval.OrnamentNumberSymbol = this.OrnamentNumberSymbol; // the displayed ornament number rval.MidiChordSliderDefs = null; MidiChordSliderDefs m = this.MidiChordSliderDefs; if(m != null) { List<byte> pitchWheelMsbs = NewListByteOrNull(m.PitchWheelMsbs); List<byte> panMsbs = NewListByteOrNull(m.PanMsbs); List<byte> modulationWheelMsbs = NewListByteOrNull(m.ModulationWheelMsbs); List<byte> expressionMsbs = NewListByteOrNull(m.ExpressionMsbs); if(pitchWheelMsbs != null || panMsbs != null || modulationWheelMsbs != null || expressionMsbs != null) rval.MidiChordSliderDefs = new MidiChordSliderDefs(pitchWheelMsbs, panMsbs, modulationWheelMsbs, expressionMsbs); } List<BasicMidiChordDef> newBs = new List<BasicMidiChordDef>(); foreach(BasicMidiChordDef b in BasicMidiChordDefs) { List<byte> pitches = new List<byte>(b.Pitches); List<byte> velocities = new List<byte>(b.Velocities); newBs.Add(new BasicMidiChordDef(b.MsDuration, b.BankIndex, b.PatchIndex, b.HasChordOff, pitches, velocities)); } rval.BasicMidiChordDefs = newBs; rval.MsDuration = this.MsDuration; return rval; }
/// <summary> /// Returns a new Trk having msDuration and midiChannel, whose MidiChordDefs are created from this MidiChordDef's BasicMidiChordDefs. /// If a non-null gamut argument is given, a check is made (in the Trk constructor) to ensure that it contains /// all the pitches (having velocity greater than 1) in this MidiChordDef. /// Each new MidiChordDef has one BasicMidiChordDef, which is a copy of a BasicMidiChordDef from this MidiChordDef. /// The new MidiChordDef's notated pitches and velocities are the same as its BasicMidiChordDef's. /// The durations of the returned MidiChordDefs are in proportion to the durations of the original BasicMidichordDefs. /// This MidiChordDef is not changed by calling this function. /// </summary> /// <param name="msDuration">The duration of the returned Trk</param> /// <param name="midiChannel">The channel of the returned Trk</param> /// <param name="gamut">The gamut must contain all the pitches in this MidiChordDef.</param> public Trk ToTrk(int msDuration, int midiChannel) { List<IUniqueDef> iuds = new List<IUniqueDef>(); foreach(BasicMidiChordDef bmcd in this.BasicMidiChordDefs) { // this constructor checks that pitches are in range 0..127, and velocities are in range 1..127. MidiChordDef mcd = new MidiChordDef(bmcd.Pitches, bmcd.Velocities, bmcd.MsDuration, bmcd.HasChordOff); mcd.BasicMidiChordDefs[0].BankIndex = bmcd.BankIndex; mcd.BasicMidiChordDefs[0].PatchIndex = bmcd.PatchIndex; mcd.BasicMidiChordDefs[0].HasChordOff = bmcd.HasChordOff; iuds.Add(mcd); } Trk trk = new Trk(midiChannel, 0, iuds); trk.MsDuration = msDuration; // calls Trk.SetMsPositionsReFirstUD(); return trk; }