public static void SplitChordsAtDistance(this MidiFile midiFile, double ratio, TimeSpanType lengthType, LengthedObjectTarget from, long notesTolerance = 0)
        {
            ThrowIfArgument.IsNull(nameof(midiFile), midiFile);
            ThrowIfArgument.IsOutOfRange(nameof(ratio),
                                         ratio,
                                         LengthedObjectsSplitter <Chord> .ZeroRatio,
                                         LengthedObjectsSplitter <Chord> .FullLengthRatio,
                                         $"Ratio is out of [{LengthedObjectsSplitter<Chord>.ZeroRatio}; {LengthedObjectsSplitter<Chord>.FullLengthRatio}] range.");
            ThrowIfArgument.IsInvalidEnumValue(nameof(lengthType), lengthType);
            ThrowIfArgument.IsInvalidEnumValue(nameof(from), from);
            ThrowIfNotesTolerance.IsNegative(nameof(notesTolerance), notesTolerance);

            var tempoMap = midiFile.GetTempoMap();

            midiFile.GetTrackChunks().SplitChordsAtDistance(ratio, lengthType, from, tempoMap, notesTolerance);
        }
        /// <summary>
        /// Returns an <see cref="IntervalDefinition"/> by the specified half steps number and
        /// interval's direction.
        /// </summary>
        /// <param name="interval">The interval as a number of half steps away.</param>
        /// <param name="direction">The direction of an interval (up or down).</param>
        /// <returns>An <see cref="IntervalDefinition"/> with the specified interval and direction.</returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="direction"/> specified an
        /// invalid value.</exception>
        public static IntervalDefinition Get(SevenBitNumber interval, IntervalDirection direction)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(direction), direction);

            if (!_cache.TryGetValue(interval, out Dictionary <IntervalDirection, IntervalDefinition> intervalDefinitions))
            {
                _cache.Add(interval, intervalDefinitions = new Dictionary <IntervalDirection, IntervalDefinition>());
            }

            if (!intervalDefinitions.TryGetValue(direction, out IntervalDefinition intervalDefinition))
            {
                intervalDefinitions.Add(direction, intervalDefinition = new IntervalDefinition(interval, direction));
            }

            return(intervalDefinition);
        }
Beispiel #3
0
        /// <summary>
        /// Splits notes contained in the specified collection of <see cref="TrackChunk"/> by the
        /// specified ratio of a note's length measuring it from the note's start or end.
        /// For example, 0.5 means splitting at the center of a note.
        /// </summary>
        /// <param name="trackChunks">Collection of <see cref="TrackChunk"/> to split notes in.</param>
        /// <param name="ratio">Ratio of a note's length to split by. Valid values are from 0 to 1.</param>
        /// <param name="lengthType">The type a note's length should be processed according to.</param>
        /// <param name="from">Point of a note distance should be measured from.</param>
        /// <param name="tempoMap">Tempo map used for distances calculations.</param>
        /// <exception cref="ArgumentNullException"><paramref name="trackChunks"/> is null. -or-
        /// <paramref name="tempoMap"/> is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="ratio"/> is out of valid range.</exception>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="lengthType"/> specified an invalid value. -or-
        /// <paramref name="from"/> specified an invalid value.</exception>
        public static void SplitNotesAtDistance(this IEnumerable <TrackChunk> trackChunks, double ratio, TimeSpanType lengthType, LengthedObjectTarget from, TempoMap tempoMap)
        {
            ThrowIfArgument.IsNull(nameof(trackChunks), trackChunks);
            ThrowIfArgument.IsOutOfRange(nameof(ratio),
                                         ratio,
                                         LengthedObjectsSplitter <Note> .ZeroRatio,
                                         LengthedObjectsSplitter <Note> .FullLengthRatio,
                                         $"Ratio is out of [{LengthedObjectsSplitter<Note>.ZeroRatio}; {LengthedObjectsSplitter<Note>.FullLengthRatio}] range.");
            ThrowIfArgument.IsInvalidEnumValue(nameof(lengthType), lengthType);
            ThrowIfArgument.IsInvalidEnumValue(nameof(from), from);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);

            foreach (var trackChunk in trackChunks)
            {
                trackChunk.SplitNotesAtDistance(ratio, lengthType, from, tempoMap);
            }
        }
        /// <summary>
        /// Gets chunks converter which is appropriate for a passed MIDI file format.
        /// </summary>
        /// <param name="format">MIDI file format to get <see cref="IChunksConverter"/> for.</param>
        /// <returns>An instance of the <see cref="IChunksConverter"/> appropriate for
        /// <paramref name="format"/>.</returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="format"/> specified an invalid value.</exception>
        /// <exception cref="NotSupportedException"><paramref name="format"/> is not supported.</exception>
        public static IChunksConverter GetConverter(MidiFileFormat format)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(format), format);

            switch (format)
            {
            case MidiFileFormat.SingleTrack:
                return(new SingleTrackChunksConverter());

            case MidiFileFormat.MultiTrack:
                return(new MultiTrackChunksConverter());

            case MidiFileFormat.MultiSequence:
                return(new MultiSequenceChunksConverter());
            }

            throw new NotSupportedException($"Converter for the {format} format is not supported.");
        }
        /// <summary>
        /// Gets <see cref="NoteName"/> corresponding to the specified degree of a musical scale.
        /// </summary>
        /// <param name="scale"><see cref="Scale"/> to get degree of.</param>
        /// <param name="degree"><see cref="ScaleDegree"/> representing a degree of the
        /// <paramref name="scale"/>.</param>
        /// <returns>The degree of the scale.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="scale"/> is null.</exception>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="degree"/> specified an
        /// invalid value.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="degree"/> is out of
        /// range for the <paramref name="scale"/>.</exception>
        public static NoteName GetDegree(this Scale scale, ScaleDegree degree)
        {
            ThrowIfArgument.IsNull(nameof(scale), scale);
            ThrowIfArgument.IsInvalidEnumValue(nameof(degree), degree);

            var degreeNumber = (int)degree;

            if (degreeNumber >= scale.Intervals.Count())
            {
                throw new ArgumentOutOfRangeException(nameof(degree),
                                                      degree,
                                                      "Degree is out of range for the scale.");
            }

            return(scale.GetNotes()
                   .Skip(degreeNumber)
                   .First()
                   .NoteName);
        }
Beispiel #6
0
        /// <summary>
        /// Returns an <see cref="Interval"/> by the specified half steps number and
        /// interval's direction.
        /// </summary>
        /// <param name="intervalSize">The size of an interval as a number of half steps away.</param>
        /// <param name="direction">The direction of an interval (up or down).</param>
        /// <returns>An <see cref="Interval"/> with the specified interval and direction.</returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="direction"/> specified an
        /// invalid value.</exception>
        public static Interval Get(SevenBitNumber intervalSize, IntervalDirection direction)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(direction), direction);

            Dictionary <IntervalDirection, Interval> intervals;

            if (!_cache.TryGetValue(intervalSize, out intervals))
            {
                _cache.Add(intervalSize, intervals = new Dictionary <IntervalDirection, Interval>());
            }

            Interval cachedInterval;

            if (!intervals.TryGetValue(direction, out cachedInterval))
            {
                intervals.Add(direction, cachedInterval = new Interval(intervalSize, direction));
            }

            return(cachedInterval);
        }
Beispiel #7
0
        /// <summary>
        /// Gets a value indicating whether quality is applicable to the specified interval number (1 and greater) or not.
        /// </summary>
        /// <param name="intervalQuality">Interval quality to check whether it's applicable to
        /// <paramref name="intervalNumber"/> or not.</param>
        /// <param name="intervalNumber">Interval number to check whether <paramref name="intervalQuality"/> is
        /// applicable to it or not.</param>
        /// <returns>true if <paramref name="intervalQuality"/> is applicable to <paramref name="intervalNumber"/>;
        /// otherwise, false.</returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="intervalQuality"/> specified an
        /// invalid value.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="intervalNumber"/> is less than 1.</exception>
        public static bool IsQualityApplicable(IntervalQuality intervalQuality, int intervalNumber)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(intervalQuality), intervalQuality);
            ThrowIfArgument.IsLessThan(nameof(intervalNumber), intervalNumber, 1, "Interval number is less than 1.");

            switch (intervalQuality)
            {
            case IntervalQuality.Perfect:
                return(IsPerfect(intervalNumber));

            case IntervalQuality.Minor:
            case IntervalQuality.Major:
                return(!IsPerfect(intervalNumber));

            case IntervalQuality.Diminished:
                return(intervalNumber >= 2);

            case IntervalQuality.Augmented:
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Iterates through the specified collection of <see cref="Note"/> returning instances of <see cref="Note"/>
        /// and <see cref="Rest"/> where rests calculated using the specified policy.
        /// </summary>
        /// <param name="notes">Collection of <see cref="Note"/> to iterate over.</param>
        /// <param name="restSeparationPolicy">Policy which determines when rests should be returned.</param>
        /// <returns>Collection of <see cref="ITimedObject"/> where an element either <see cref="Note"/>
        /// or <see cref="Rest"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="notes"/> is null.</exception>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="restSeparationPolicy"/> specified an
        /// invalid value.</exception>
        public static IEnumerable <ILengthedObject> GetNotesAndRests(
            this IEnumerable <Note> notes,
            RestSeparationPolicy restSeparationPolicy)
        {
            ThrowIfArgument.IsNull(nameof(notes), notes);
            ThrowIfArgument.IsInvalidEnumValue(nameof(restSeparationPolicy), restSeparationPolicy);

            switch (restSeparationPolicy)
            {
            case RestSeparationPolicy.NoSeparation:
                return(GetNotesAndRests(notes,
                                        n => NoSeparationNoteDescriptor,
                                        false,
                                        false));

            case RestSeparationPolicy.SeparateByChannel:
                return(GetNotesAndRests(notes,
                                        n => n.Channel,
                                        true,
                                        false));

            case RestSeparationPolicy.SeparateByNoteNumber:
                return(GetNotesAndRests(notes,
                                        n => n.NoteNumber,
                                        false,
                                        true));

            case RestSeparationPolicy.SeparateByChannelAndNoteNumber:
                return(GetNotesAndRests(notes,
                                        n => n.GetNoteId(),
                                        true,
                                        true));
            }

            throw new NotSupportedException($"Rest separation policy {restSeparationPolicy} is not supported.");
        }
Beispiel #9
0
        /// <summary>
        /// Adds a note by the specified note name using specified velocity and length, and default octave.
        /// </summary>
        /// <param name="noteName">The name of a note.</param>
        /// <param name="length">The length of a note.</param>
        /// <param name="velocity">The velocity of a note.</param>
        /// <returns>The current <see cref="PatternBuilder"/>.</returns>
        /// <remarks>
        /// To set default octave use <see cref="SetOctave(int)"/> method. By default the octave number is 4.
        /// </remarks>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="noteName"/> specified an invalid value.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="length"/> is null.</exception>
        public PatternBuilder Note(NoteName noteName, ILength length, SevenBitNumber velocity)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(noteName), noteName);

            return(Note(_octave.GetNoteDefinition(noteName), length, velocity));
        }
        /// <summary>
        /// Gets an object that represents zero value of time span defined by the specified
        /// time span type.
        /// </summary>
        /// <param name="timeSpanType">The type of time span to get zero value.</param>
        /// <returns>An object that represents zero value of time span defined by <paramref name="timeSpanType"/>.</returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="timeSpanType"/> specified an
        /// invalid value.</exception>
        public static ITimeSpan GetZeroTimeSpan(TimeSpanType timeSpanType)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(timeSpanType), timeSpanType);

            return(ZeroTimeSpans[timeSpanType]);
        }
Beispiel #11
0
        /// <summary>
        ///     Gets an instance of the <see cref="ProgramChangeEvent" /> corresponding to the specified
        ///     General MIDI Level 1 program.
        /// </summary>
        /// <param name="program"><see cref="GeneralMidiProgram" /> to get an event for.</param>
        /// <returns>An instance of the <see cref="ProgramChangeEvent" /> corresponding to the <paramref name="program" />.</returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="program" /> specified an invalid value.</exception>
        public static MidiEvent GetProgramEvent(this GeneralMidiProgram program)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(program), program);

            return(new ProgramChangeEvent(program.AsSevenBitNumber()));
        }
Beispiel #12
0
        /// <summary>
        ///     Converts <see cref="GeneralMidiPercussion" /> to the corresponding value of the
        ///     <see cref="SevenBitNumber" /> type.
        /// </summary>
        /// <param name="percussion"><see cref="GeneralMidiPercussion" /> to convert to <see cref="SevenBitNumber" />.</param>
        /// <returns><see cref="SevenBitNumber" /> representing the <paramref name="percussion" />.</returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="percussion" /> specified an invalid value.</exception>
        public static SevenBitNumber AsSevenBitNumber(this GeneralMidiPercussion percussion)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(percussion), percussion);

            return((SevenBitNumber)(byte)percussion);
        }
Beispiel #13
0
        /// <summary>
        ///     Converts <see cref="GeneralMidiProgram" /> to the corresponding value of the
        ///     <see cref="SevenBitNumber" /> type.
        /// </summary>
        /// <param name="program"><see cref="GeneralMidiProgram" /> to convert to <see cref="SevenBitNumber" />.</param>
        /// <returns><see cref="SevenBitNumber" /> representing the <paramref name="program" />.</returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="program" /> specified an invalid value.</exception>
        public static SevenBitNumber AsSevenBitNumber(this GeneralMidiProgram program)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(program), program);

            return((SevenBitNumber)(byte)program);
        }
Beispiel #14
0
        /// <summary>
        /// Gets an instance of the <see cref="ControlChangeEvent"/> corresponding to the specified controller.
        /// </summary>
        /// <param name="controlName"><see cref="ControlName"/> to get an event for.</param>
        /// <param name="controlValue">Controller value to set to event.</param>
        /// <returns>An instance of the <see cref="ControlChangeEvent"/> corresponding to the <paramref name="controlName"/>.</returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="controlName"/> specified an invalid value.</exception>
        public static ControlChangeEvent GetControlChangeEvent(this ControlName controlName, SevenBitNumber controlValue)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(controlName), controlName);

            return(new ControlChangeEvent(controlName.AsSevenBitNumber(), controlValue));
        }
Beispiel #15
0
        /// <summary>
        /// Retrieves the duration of the playback in the specified format.
        /// </summary>
        /// <param name="durationType">Type that will represent the duration.</param>
        /// <returns>The duration of the playback as an instance of time span defined by
        /// <paramref name="durationType"/>.</returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="durationType"/>
        /// specified an invalid value.</exception>
        public ITimeSpan GetDuration(TimeSpanType durationType)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(durationType), durationType);

            return(TimeConverter.ConvertTo((MetricTimeSpan)_duration, durationType, TempoMap));
        }
Beispiel #16
0
        /// <summary>
        /// Retrieves the current time of the playback in the specified format.
        /// </summary>
        /// <param name="timeType">Type that will represent the current time.</param>
        /// <returns>The current time of the playback as an instance of time span defined by
        /// <paramref name="timeType"/>.</returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="timeType"/> specified an invalid value.</exception>
        public ITimeSpan GetCurrentTime(TimeSpanType timeType)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(timeType), timeType);

            return(TimeConverter.ConvertTo((MetricTimeSpan)_clock.CurrentTime, timeType, TempoMap));
        }
Beispiel #17
0
        /// <summary>
        ///     Gets an instance of the <see cref="NoteOffEvent" /> corresponding to the specified
        ///     General MIDI Level 1 percussion.
        /// </summary>
        /// <param name="percussion"><see cref="GeneralMidiPercussion" /> to get an event for.</param>
        /// <param name="velocity">Velocity of the <see cref="NoteOffEvent" />.</param>
        /// <returns>
        ///     An instance of the <see cref="NoteOffEvent" /> corresponding to the specified
        ///     <paramref name="percussion" />.
        /// </returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="percussion" /> specified an invalid value.</exception>
        public static NoteOffEvent GetNoteOffEvent(this GeneralMidiPercussion percussion, SevenBitNumber velocity)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(percussion), percussion);

            return(new NoteOffEvent(percussion.AsSevenBitNumber(), velocity));
        }
Beispiel #18
0
        /// <summary>
        /// Retrieves the duration of the recording in the specified format.
        /// </summary>
        /// <param name="durationType">Type that will represent the duration.</param>
        /// <returns>The duration of the recording as an instance of time span defined by
        /// <paramref name="durationType"/>.</returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="durationType"/>
        /// specified an invalid value.</exception>
        public ITimeSpan GetDuration(TimeSpanType durationType)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(durationType), durationType);

            return(TimeConverter.ConvertTo((MetricTimeSpan)_events.LastOrDefault()?.Time ?? new MetricTimeSpan(), durationType, TempoMap));
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="MidiEvent"/> with the specified event type.
        /// </summary>
        /// <param name="eventType">The type of event.</param>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="eventType"/> specified an invalid value.</exception>
        public MidiEvent(MidiEventType eventType)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(eventType), eventType);

            EventType = eventType;
        }
Beispiel #20
0
        internal static ITimeSpan Subtract(ITimeSpan timeSpan1, ITimeSpan timeSpan2, TimeSpanMode mode)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(mode), mode);

            return(new MathTimeSpan(timeSpan1, timeSpan2, MathOperation.Subtract, mode));
        }
Beispiel #21
0
        /// <summary>
        /// Converts <see cref="ControlName"/> to the corresponding value of the <see cref="SevenBitNumber"/> type.
        /// </summary>
        /// <param name="controlName"><see cref="ControlName"/> to convert to <see cref="SevenBitNumber"/>.</param>
        /// <returns><see cref="SevenBitNumber"/> representing the <paramref name="controlName"/>.</returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="controlName"/> specified an invalid value.</exception>
        public static SevenBitNumber AsSevenBitNumber(this ControlName controlName)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(controlName), controlName);

            return((SevenBitNumber)(byte)controlName);
        }