private protected override void InitializeCompositionParams(IList <IBar> chordProgression, IList <IBar> melodyInitializationSeed = null, OverallNoteDurationFeel overallNoteDurationFeel = OverallNoteDurationFeel.Medium, NotePitch minPitch = NotePitch.E2, NotePitch maxPitch = NotePitch.E6, params object[] additionalParams) { // delegate the general initialization to base class base.InitializeCompositionParams(chordProgression, melodyInitializationSeed, overallNoteDurationFeel, minPitch, maxPitch); // initialize custom settings of the genetic algorithm _currentGeneration = 0; _candidates = new List <MelodyCandidate>(MaxPopulationSize); if (additionalParams.Length > 0 && additionalParams[0] is MelodyEvaluatorsWeights) { EvaluatorsWeights = additionalParams[0] as MelodyEvaluatorsWeights; } else { EvaluatorsWeights = new MelodyEvaluatorsWeights(); } }
/// <summary> /// Composes a solo-melody over this composition's midi playback file and chord progression, /// using the additional preferences and constraints parameters. /// </summary> /// <returns> A new midi file containing the composed solo-melody. </returns> /// <param name="strategy">Requested composition strategy algorithm for composing the melody. </param> /// <param name="overallNoteDurationFeel">Requested generic density overall feeling of the outcome melody.</param> /// <param name="musicalInstrument">Requested virtual music instrumen tha would play the output melody.</param> /// <param name="pitchRangeSource">Determins whether to set the pitch range from the original melody in the /// midi file, or from the custom values mentiones in <paramref name="minPitch"/> /// and <paramref name="maxPitch"/>.</param> /// <param name="minPitch">Requested lowest available pitch that would can be used for the composition. /// This is relevant only if <paramref name="pitchRangeSource"/> was set to /// <see cref="PitchRangeSource.Custom"/>.</param> /// <param name="maxPitch">Requested highest available pitch that would can be used for the composition. /// This is relevant only if <paramref name="pitchRangeSource"/> was set to /// <see cref="PitchRangeSource.Custom"/>.</param> /// <param name="useExistingMelodyAsSeed">If set, then the original melody might be used in initialization phase /// of the compositon strategy algorithm. This is relevant only if the /// midi file contains an existing melody to begin with. /// Moreover, this feature is implementation dependent: some strategies /// might make high use of original melody as the main initialization seed /// and some may not use it at all.</param> /// <param name="customParams"> Currently unused. This a placeholder for additional parameters that could be used /// in the future to extened existing implementations and developing new ones without /// breaking the existing interface. </param> /// <returns></returns> public IMidiFile[] Compose( CompositionStrategy strategy = CompositionStrategy.GeneticAlgorithmStrategy, OverallNoteDurationFeel overallNoteDurationFeel = OverallNoteDurationFeel.Medium, MusicalInstrument musicalInstrument = MusicalInstrument.AcousticGrandPiano, PitchRangeSource pitchRangeSource = PitchRangeSource.Custom, NotePitch minPitch = DefaultMinPitch, NotePitch maxPitch = DefaultMaxPitch, bool useExistingMelodyAsSeed = true, params object[] customParams) { // set compositor according to composition strategy _composer = ComposerFactory.CreateComposer(strategy); // make a copy of the input midi file for the output file MidiOutputFile = MidiFactory.CreateMidiFile(_midiInputFilePath); /* if the midi file already contains a melody track, * extract it out of the intended midi output file * and if requested, save it in a separate bar sequence for further usage * as a melody initialization seed for the composition if needed. */ if (_melodyTrackIndex.HasValue && _melodyTrackIndex.Value != MelodyTrackIndex.NoMelodyTrackInFile) { /* if the existing melody should serve as a seed, * initialize a bar-sequence place-holder for it, * based on the chord progression structure */ _melodySeed = useExistingMelodyAsSeed ? CompositionContext.CloneChordProgressionBars(ChordProgression) : null; /* extract/remove the existing melody from midi file and * save it in the place holder if it was initialized */ MidiOutputFile.ExtractMelodyTrack((byte)_melodyTrackIndex, _melodySeed); } // initialize pitch range from midi file if requested if (pitchRangeSource == PitchRangeSource.MidiFile && _melodyTrackIndex.HasValue) { NotePitch?lowestPitch, highestPitch; MidiInputFile.GetPitchRangeForTrack((int)_melodyTrackIndex, out lowestPitch, out highestPitch); if (lowestPitch.HasValue && highestPitch.HasValue) { minPitch = (NotePitch)lowestPitch; maxPitch = (NotePitch)highestPitch; } } // validate pitch range is at least one octave long (12 semi-tones) if (!IsPitchRangeValid((int)minPitch, (int)maxPitch, out string errorMessage)) { throw new ArgumentException(errorMessage); } // compose a new melody IList <IBar>[] composedMelodies = _composer.Compose( chordProgression: ChordProgression, melodyInitializationSeed: _melodySeed, overallNoteDurationFeel: overallNoteDurationFeel, minPitch: minPitch, maxPitch: maxPitch, customParams: customParams) .ToArray(); // Embed each new generated melody into a new separate midi file IMidiFile[] midiOutputs = new IMidiFile[composedMelodies.Length]; for (int i = 0; i < composedMelodies.Length; i++) { midiOutputs[i] = MidiFactory.CreateMidiFile(_midiInputFilePath); midiOutputs[i].ExtractMelodyTrack((byte)_melodyTrackIndex); midiOutputs[i].EmbedMelody(composedMelodies[i], musicalInstrument); midiOutputs[i].FadeOut(); } // save first output in dedicated placeholder MidiOutputFile = midiOutputs[0]; // return the first composed melody from the output return(midiOutputs); }