private List<List<VoiceDef>> GetBars(Trk track, List<int> nChordsPerSystem) { List<Trk> consecutiveBars = new List<Trk>(); // barlineMsPositions will contain both msPos=0 and the position of the final barline List<int> barlineMsPositions = new List<int>() { 0 }; int trackIndex = 0; int msPositionReContainer = 0; foreach(int nChords in nChordsPerSystem) { Trk trk = new Trk(0, msPositionReContainer, new List<IUniqueDef>()); for(int i = 0; i < nChords; ++i) { trk.Add(track[trackIndex++]); } msPositionReContainer = trk.EndMsPositionReFirstIUD; barlineMsPositions.Add(msPositionReContainer); consecutiveBars.Add(trk); } List<List<VoiceDef>> bars = new List<List<VoiceDef>>(); foreach(Trk trk in consecutiveBars) { List<VoiceDef> bar = new List<VoiceDef>() { trk }; bars.Add(bar); } return bars; }
/// <summary> /// A Block contains a list of VoiceDefs consisting of a group of Trks followed by InputVoiceDefs. /// This constructor creates a MainBlock consisting of the concatenation of the Blocks in the argument blockList. /// The initialClefs are set to the clefs in initialClefsPerChannel. /// initialClefsPerChannel contains the clefs for the Trks followed by the clefs for the clefs for the InputVoiceDefs. /// Note that initialClefsPerChannel contains a clef for each channel, regardless of whether it is going to be printed or not. /// The channels for both Trks and InputVoiceDefs are in ascending order. Their order from top to bottom in the score is determined later. /// </summary> /// <param name="initialClefPerChannel">The clefs to set at the start of each Trk followed by the clefs for each InputVoiceDef</param> /// <param name="blockList">A list of Blocks that will be concatenated to become this MainBlock.</param> public MainBlock(List<string> initialClefPerChannel, List<Block> blockList) : base() { Debug.Assert(blockList != null && blockList.Count > 0); Block block1 = blockList[0]; int nTrks = block1.Trks.Count; int nInputVoiceDefs = block1.InputVoiceDefs.Count; #region conditions Debug.Assert(initialClefPerChannel.Count == (nTrks + nInputVoiceDefs)); foreach(Block block in blockList) { Debug.Assert(block.Trks.Count == nTrks); Debug.Assert(block.InputVoiceDefs.Count == nInputVoiceDefs); for(int trkIndex = 0; trkIndex < nTrks; ++trkIndex) { // Achtung: Trk midiChannels are those defined in the algorithm's MidiChannelIndexPerOutputVoice. // The output channels must be in ascending oder, **_but_do_not_need_to_be_contiguous_**. // See comment at CompositionAlgorithm.MidiChannelIndexPerOutputVoice. Debug.Assert(block.Trks[trkIndex].MidiChannel == block1.Trks[trkIndex].MidiChannel); } for(int ivdIndex = 0; ivdIndex < nInputVoiceDefs; ++ivdIndex) { // Input channels are in ascending order, starting at 0, and are contiguous. Debug.Assert(block.Trks[ivdIndex].MidiChannel == ivdIndex); } } #endregion conditions for(int i = 0; i < nTrks; ++i) { int channel = block1.Trks[i].MidiChannel; VoiceDef trk = new Trk(channel); trk.Add(new ClefChangeDef(initialClefPerChannel[channel], 0)); _voiceDefs.Add(trk); } int inputVoiceIndex = Trks.Count; for(int i = 0; i < nInputVoiceDefs; ++i) { VoiceDef inputVoiceDef = new InputVoiceDef(i); inputVoiceDef.Add(new ClefChangeDef(initialClefPerChannel[inputVoiceIndex++], 0)); _voiceDefs.Add(inputVoiceDef); } foreach(Block block in blockList) { this.Concat(block); } }
/// <summary> /// Makes both tracks the same length by adding rests at the beginnings and ends. /// The Alignment is found using this.MsPositionReContainer and trk2.MsPositionReContainer /// </summary> private void AlignAndJustifyWith(Trk trk2) { this.Trim(); if(this.MsPositionReContainer > 0) { this.Insert(0, new RestDef(0, this.MsPositionReContainer)); this.MsPositionReContainer = 0; } trk2.Trim(); if(trk2.MsPositionReContainer > 0) { trk2.Insert(0, new RestDef(0, trk2.MsPositionReContainer)); trk2.MsPositionReContainer = 0; } int lengthDiff = trk2.MsDuration - this.MsDuration; if(lengthDiff > 0) { this.Add(new RestDef(0, lengthDiff)); } else if(lengthDiff < 0) { trk2.Add(new RestDef(0, -lengthDiff)); } }