Ejemplo n.º 1
0
        /// <summary>
        /// Shrinks the current time span by dividing its length by the specified divisor.
        /// </summary>
        /// <param name="divisor">Divisor to shrink the time span by.</param>
        /// <returns>Time span that is the current time span shrinked by the <paramref name="divisor"/>.</returns>
        public ITimeSpan Divide(double divisor)
        {
            ThrowIfArgument.IsNonpositive(nameof(divisor), divisor, "Divisor is zero or negative.");

            return(new MusicalTimeSpan(Numerator * FractionPartMultiplier,
                                       MathUtilities.RoundToLong(Denominator * MathUtilities.Round(divisor, NumberOfDigitsAfterDecimalPoint) * FractionPartMultiplier)));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Shrinks the current time span by dividing its length by the specified divisor.
        /// </summary>
        /// <param name="divisor">Divisor to shrink the time span by.</param>
        /// <returns>Time span that is the current time span shrinked by the <paramref name="divisor"/>.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="divisor"/> is zero or negative.</exception>
        public ITimeSpan Divide(double divisor)
        {
            ThrowIfArgument.IsNonpositive(nameof(divisor), divisor, "Divisor is zero or negative.");

            return(new BarBeatFractionTimeSpan(MathUtilities.RoundToLong(Bars / divisor),
                                               Beats / divisor));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Creates an instance of the <see cref="Tempo"/> with the specified number of
        /// beats per minute.
        /// </summary>
        /// <param name="beatsPerMinute">Number of beats per minute.</param>
        /// <returns>An instance of the <see cref="Tempo"/> which represents tempo as specified
        /// number of beats per minute.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="beatsPerMinute"/>
        /// is zero or negative.</exception>
        public static Tempo FromBeatsPerMinute(int beatsPerMinute)
        {
            ThrowIfArgument.IsNonpositive(nameof(beatsPerMinute),
                                          beatsPerMinute,
                                          "Number of beats per minute is zero or negative.");

            return(new Tempo(MathUtilities.RoundToLong((double)MicrosecondsInMinute / beatsPerMinute)));
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Creates an instance of the <see cref="Tempo"/> with the specified number of
        /// milliseconds per quarter note.
        /// </summary>
        /// <param name="millisecondsPerQuarterNote">Number of milliseconds per quarter note.</param>
        /// <returns>An instance of the <see cref="Tempo"/> which represents tempo as specified
        /// number of milliseconds per quarter note.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="millisecondsPerQuarterNote"/>
        /// is zero or negative.</exception>
        public static Tempo FromMillisecondsPerQuarterNote(long millisecondsPerQuarterNote)
        {
            ThrowIfArgument.IsNonpositive(nameof(millisecondsPerQuarterNote),
                                          millisecondsPerQuarterNote,
                                          "Number of milliseconds per quarter note is zero or negative.");

            return(new Tempo(millisecondsPerQuarterNote * MicrosecondsInMillisecond));
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Tempo"/> with the specified number of
        /// microseconds per quarter note.
        /// </summary>
        /// <param name="microsecondsPerQuarterNote">Number of microseconds per quarter note.</param>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="microsecondsPerQuarterNote"/>
        /// is zero or negative.</exception>
        public Tempo(long microsecondsPerQuarterNote)
        {
            ThrowIfArgument.IsNonpositive(nameof(microsecondsPerQuarterNote),
                                          microsecondsPerQuarterNote,
                                          "Number of microseconds per quarter note is zero or negative.");

            MicrosecondsPerQuarterNote = microsecondsPerQuarterNote;
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Divides the specified <see cref="MusicalTimeSpan"/> by a number.
        /// </summary>
        /// <param name="timeSpan">The <see cref="MusicalTimeSpan"/> to divide by <paramref name="number"/>.</param>
        /// <param name="number">The multiplier.</param>
        /// <returns>An object whose value is the result of division of <paramref name="timeSpan"/> by
        /// <paramref name="number"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="timeSpan"/> is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="number"/> is negative.</exception>
        public static MusicalTimeSpan operator /(MusicalTimeSpan timeSpan, long number)
        {
            ThrowIfArgument.IsNull(nameof(timeSpan), timeSpan);
            ThrowIfArgument.IsNonpositive(nameof(number), number, "Number is zero or negative.");

            return(new MusicalTimeSpan(timeSpan.Numerator,
                                       timeSpan.Denominator * number));
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Shrinks the current time span by dividing its length by the specified divisor.
        /// </summary>
        /// <param name="divisor">Divisor to shrink the time span by.</param>
        /// <returns>Time span that is the current time span shrinked by the <paramref name="divisor"/>.</returns>
        public ITimeSpan Divide(double divisor)
        {
            ThrowIfArgument.IsNonpositive(nameof(divisor), divisor, "Divisor is zero or negative.");

            return(new BarBeatTimeSpan((long)Math.Round(Bars / divisor),
                                       (long)Math.Round(Beats / divisor),
                                       (long)Math.Round(Ticks / divisor)));
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Returns a tuplet based on the current <see cref="MusicalTimeSpan"/>.
        /// </summary>
        /// <param name="tupletNotesCount">Notes count of a tuplet to construct.</param>
        /// <param name="tupletSpaceSize">Space of a tuplet to construct.</param>
        /// <returns>A tuplet based on the current <see cref="MusicalTimeSpan"/>.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="tupletNotesCount"/> is zero
        /// or negative. -or- <paramref name="tupletSpaceSize"/> is zero or negative.</exception>
        public MusicalTimeSpan Tuplet(int tupletNotesCount, int tupletSpaceSize)
        {
            ThrowIfArgument.IsNonpositive(nameof(tupletNotesCount), tupletNotesCount, "Tuplet's notes count is zero or negative.");
            ThrowIfArgument.IsNonpositive(nameof(tupletSpaceSize), tupletSpaceSize, "Tuplet's space size is zero or negative.");

            return(new MusicalTimeSpan(Numerator * tupletSpaceSize,
                                       Denominator * tupletNotesCount));
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Changes denominator of the current <see cref="MusicalTimeSpan"/>.
        /// </summary>
        /// <param name="denominator">New denominator.</param>
        /// <returns>An instance of the <see cref="MusicalTimeSpan"/> which represents the same time span as
        /// the original one but with the specified denominator.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="denominator"/> is zero or negative.</exception>
        public MusicalTimeSpan ChangeDenominator(long denominator)
        {
            ThrowIfArgument.IsNonpositive(nameof(denominator), denominator, "Denominator is zero or negative.");

            var numerator = MathUtilities.RoundToLong((double)denominator / Denominator * Numerator);

            return(new MusicalTimeSpan(numerator, denominator, false));
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Splits chords contained in the specified <see cref="TrackChunk"/> into the specified number
        /// of parts of the equal length.
        /// </summary>
        /// <remarks>
        /// If a chord has zero length, it will be split into the specified number of parts of zero length.
        /// </remarks>
        /// <param name="trackChunk"><see cref="TrackChunk"/> to split chords in.</param>
        /// <param name="partsNumber">The number of parts to split chords into.</param>
        /// <param name="lengthType">Type of a part's length.</param>
        /// <param name="tempoMap">Tempo map used to calculate times to split by.</param>
        /// <param name="settings">Settings accoridng to which chords should be detected and built.</param>
        /// <exception cref="ArgumentNullException">
        /// <para>One of the following errors occured:</para>
        /// <list type="bullet">
        /// <item>
        /// <description><paramref name="trackChunk"/> is <c>null</c>.</description>
        /// </item>
        /// <item>
        /// <description><paramref name="tempoMap"/> is <c>null</c>.</description>
        /// </item>
        /// </list>
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="partsNumber"/> is zero or negative.</exception>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="lengthType"/> specified an invalid value.</exception>
        public static void SplitChordsByPartsNumber(this TrackChunk trackChunk, int partsNumber, TimeSpanType lengthType, TempoMap tempoMap, ChordDetectionSettings settings = null)
        {
            ThrowIfArgument.IsNull(nameof(trackChunk), trackChunk);
            ThrowIfArgument.IsNonpositive(nameof(partsNumber), partsNumber, "Parts number is zero or negative.");
            ThrowIfArgument.IsInvalidEnumValue(nameof(lengthType), lengthType);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);

            SplitTrackChunkChords(trackChunk, (splitter, chords) => splitter.SplitByPartsNumber(chords, partsNumber, lengthType, tempoMap), settings);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Splits notes contained in the specified <see cref="TrackChunk"/> into the specified number
        /// of parts of the equal length.
        /// </summary>
        /// <remarks>
        /// If a note has zero length, it will be splitted into the specified number of parts of zero length.
        /// </remarks>
        /// <param name="trackChunk"><see cref="TrackChunk"/> to split notes in.</param>
        /// <param name="partsNumber">The number of parts to split notes into.</param>
        /// <param name="lengthType">Type of a part's length.</param>
        /// <param name="tempoMap">Tempo map used to calculate times to split by.</param>
        /// <exception cref="ArgumentNullException"><paramref name="trackChunk"/> is null. -or-
        /// <paramref name="tempoMap"/> is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="partsNumber"/> is zero or negative.</exception>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="lengthType"/> specified an invalid value.</exception>
        public static void SplitNotesByPartsNumber(this TrackChunk trackChunk, int partsNumber, TimeSpanType lengthType, TempoMap tempoMap)
        {
            ThrowIfArgument.IsNull(nameof(trackChunk), trackChunk);
            ThrowIfArgument.IsNonpositive(nameof(partsNumber), partsNumber, "Parts number is zero or negative.");
            ThrowIfArgument.IsInvalidEnumValue(nameof(lengthType), lengthType);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);

            SplitTrackChunkNotes(trackChunk, (splitter, notes) => splitter.SplitByPartsNumber(notes, partsNumber, lengthType, tempoMap));
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Splits chords contained in the specified <see cref="TrackChunk"/> into the specified number
        /// of parts of the equal length.
        /// </summary>
        /// <remarks>
        /// If a chord has zero length, it will be splitted into the specified number of parts of zero length.
        /// </remarks>
        /// <param name="trackChunk"><see cref="TrackChunk"/> to split chords in.</param>
        /// <param name="partsNumber">The number of parts to split chords into.</param>
        /// <param name="lengthType">Type of a part's length.</param>
        /// <param name="tempoMap">Tempo map used to calculate times to split by.</param>
        /// <param name="notesTolerance">Notes tolerance that defines maximum distance of notes from the
        /// start of the first note of a chord. Notes within this tolerance will be considered as a chord.</param>
        /// <exception cref="ArgumentNullException"><paramref name="trackChunk"/> is null. -or-
        /// <paramref name="tempoMap"/> is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="partsNumber"/> is zero or negative. -or-
        /// <paramref name="notesTolerance"/> is negative.</exception>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="lengthType"/> specified an invalid value.</exception>
        public static void SplitChordsByPartsNumber(this TrackChunk trackChunk, int partsNumber, TimeSpanType lengthType, TempoMap tempoMap, long notesTolerance = 0)
        {
            ThrowIfArgument.IsNull(nameof(trackChunk), trackChunk);
            ThrowIfArgument.IsNonpositive(nameof(partsNumber), partsNumber, "Parts number is zero or negative.");
            ThrowIfArgument.IsInvalidEnumValue(nameof(lengthType), lengthType);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfNotesTolerance.IsNegative(nameof(notesTolerance), notesTolerance);

            SplitTrackChunkChords(trackChunk, (splitter, chords) => splitter.SplitByPartsNumber(chords, partsNumber, lengthType, tempoMap), notesTolerance);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Splits notes contained in the specified <see cref="MidiFile"/> into the specified number of
        /// parts of the equal length.
        /// </summary>
        /// <remarks>
        /// If a note has zero length, it will be splitted into the specified number of parts of zero length.
        /// </remarks>
        /// <param name="midiFile"><see cref="MidiFile"/> to split notes in.</param>
        /// <param name="partsNumber">The number of parts to split notes into.</param>
        /// <param name="lengthType">Type of a part's length.</param>
        /// <exception cref="ArgumentNullException"><paramref name="midiFile"/> is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="partsNumber"/> is zero or negative.</exception>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="lengthType"/> specified an invalid value.</exception>
        public static void SplitNotesByPartsNumber(this MidiFile midiFile, int partsNumber, TimeSpanType lengthType)
        {
            ThrowIfArgument.IsNull(nameof(midiFile), midiFile);
            ThrowIfArgument.IsNonpositive(nameof(partsNumber), partsNumber, "Parts number is zero or negative.");
            ThrowIfArgument.IsInvalidEnumValue(nameof(lengthType), lengthType);

            var tempoMap = midiFile.GetTempoMap();

            midiFile.GetTrackChunks().SplitNotesByPartsNumber(partsNumber, lengthType, tempoMap);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MusicalTimeSpan"/> with the specified
        /// numerator and denominator of the fraction of the whole note's length.
        /// </summary>
        /// <param name="numerator">The numerator of fraction of the whole note's length.</param>
        /// <param name="denominator">The denominator of fraction of the whole note's length.</param>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="numerator"/> is negative. -or-
        /// <paramref name="denominator"/> is zero or negative.</exception>
        public MusicalTimeSpan(long numerator, long denominator)
        {
            ThrowIfArgument.IsNegative(nameof(numerator), numerator, "Numerator is negative.");
            ThrowIfArgument.IsNonpositive(nameof(denominator), denominator, "Denominator is negative.");

            var greatestCommonDivisor = MathUtilities.GreatestCommonDivisor(numerator, denominator);

            Numerator   = numerator / greatestCommonDivisor;
            Denominator = denominator / greatestCommonDivisor;
        }
        /// <summary>
        /// Splits objects into the specified number of parts of the equal length.
        /// </summary>
        /// <remarks>
        /// Nulls will not be splitted and will be returned as nulls. If an object has zero length,
        /// it will be splitted into the specified number of parts of zero length.
        /// </remarks>
        /// <param name="objects">Objects to split.</param>
        /// <param name="partsNumber">The number of parts to split objects into.</param>
        /// <param name="lengthType">Type of a part's length.</param>
        /// <param name="tempoMap">Tempo map used to calculate times to split by.</param>
        /// <returns>Objects that are result of splitting <paramref name="objects"/> going in the same
        /// order as elements of <paramref name="objects"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="objects"/> is null. -or-
        /// <paramref name="tempoMap"/> is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="partsNumber"/> is zero or negative.</exception>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="lengthType"/> specified an invalid value.</exception>
        public IEnumerable <TObject> SplitByPartsNumber(IEnumerable <TObject> objects, int partsNumber, TimeSpanType lengthType, TempoMap tempoMap)
        {
            ThrowIfArgument.IsNull(nameof(objects), objects);
            ThrowIfArgument.IsNonpositive(nameof(partsNumber), partsNumber, "Parts number is zero or negative.");
            ThrowIfArgument.IsInvalidEnumValue(nameof(lengthType), lengthType);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);

            foreach (var obj in objects)
            {
                if (obj == null)
                {
                    yield return(default(TObject));

                    continue;
                }

                if (partsNumber == 1)
                {
                    yield return(CloneObject(obj));

                    continue;
                }

                if (obj.Length == 0)
                {
                    foreach (var i in Enumerable.Range(0, partsNumber))
                    {
                        yield return(CloneObject(obj));
                    }

                    continue;
                }

                var time = obj.Time;
                var tail = CloneObject(obj);

                for (int partsRemaining = partsNumber; partsRemaining > 1 && tail != null; partsRemaining--)
                {
                    var length     = tail.LengthAs(lengthType, tempoMap);
                    var partLength = length.Divide(partsRemaining);

                    time += LengthConverter.ConvertFrom(partLength, time, tempoMap);

                    var parts = SplitObject(tail, time);
                    yield return(parts.LeftPart);

                    tail = parts.RightPart;
                }

                if (tail != null)
                {
                    yield return(tail);
                }
            }
        }
Ejemplo n.º 16
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="TimeSignature" /> with the specified
        ///     numerator and denominator.
        /// </summary>
        /// <param name="numerator">Numerator of the time signature which defines number of beats.</param>
        /// <param name="denominator">Denominator of the time signature which defines beat length.</param>
        /// <exception cref="ArgumentOutOfRangeException">
        ///     <paramref name="numerator" /> is zero or negative. -or-
        ///     <paramref name="denominator" /> is zero or negative. -or- <paramref name="denominator" /> is not a
        ///     power of two.
        /// </exception>
        public TimeSignature(int numerator, int denominator)
        {
            ThrowIfArgument.IsNonpositive(nameof(numerator), numerator, "Numerator is zero or negative.");
            ThrowIfArgument.IsNonpositive(nameof(denominator), denominator, "Denominator is zero or negative.");
            ThrowIfArgument.DoesntSatisfyCondition(nameof(denominator),
                                                   denominator,
                                                   MathUtilities.IsPowerOfTwo,
                                                   "Denominator is not a power of two.");

            Numerator   = numerator;
            Denominator = denominator;
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Splits notes contained in the specified collection of <see cref="TrackChunk"/> into the
        /// specified number of parts of the equal length.
        /// </summary>
        /// <remarks>
        /// If a note has zero length, it will be splitted into the specified number of parts of zero length.
        /// </remarks>
        /// <param name="trackChunks">Collection of <see cref="TrackChunk"/> to split notes in.</param>
        /// <param name="partsNumber">The number of parts to split notes into.</param>
        /// <param name="lengthType">Type of a part's length.</param>
        /// <param name="tempoMap">Tempo map used to calculate times to split by.</param>
        /// <exception cref="ArgumentNullException"><paramref name="trackChunks"/> is null. -or-
        /// <paramref name="tempoMap"/> is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="partsNumber"/> is zero or negative.</exception>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="lengthType"/> specified an invalid value.</exception>
        public static void SplitNotesByPartsNumber(this IEnumerable <TrackChunk> trackChunks, int partsNumber, TimeSpanType lengthType, TempoMap tempoMap)
        {
            ThrowIfArgument.IsNull(nameof(trackChunks), trackChunks);
            ThrowIfArgument.IsNonpositive(nameof(partsNumber), partsNumber, "Parts number is zero or negative.");
            ThrowIfArgument.IsInvalidEnumValue(nameof(lengthType), lengthType);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);

            foreach (var trackChunk in trackChunks)
            {
                trackChunk.SplitNotesByPartsNumber(partsNumber, lengthType, tempoMap);
            }
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Creates an instance of the <see cref="Fraction"/> that represents the specified fraction
        /// of the whole length. Fraction can have dots and can represent tuplet's note length.
        /// </summary>
        /// <param name="fraction">Fraction of the whole length, e.g. 8 for 1/8.</param>
        /// <param name="dotsCount">Count of dots attached to the fraction.</param>
        /// <param name="tupletNotesCount">Count of notes a tuplet made up from, e.g. 3 for triplet.</param>
        /// <param name="tupletSpaceSize">Size of tuplet's space which is count of regular notes
        /// that have total length equal to the tuplet, e.g. 2 for triplet.</param>
        /// <returns><see cref="Fraction"/> that represents fraction of the whole length, e.g. 3/2 for dotted whole.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="fraction"/> is zero or negative. -or-
        /// <paramref name="dotsCount"/> is negative. -or- <paramref name="tupletNotesCount"/> is zero or
        /// negative. -or- <paramref name="tupletSpaceSize"/> is zero or negative.</exception>
        public static Fraction CreateDottedTuplet(long fraction, int dotsCount, int tupletNotesCount, int tupletSpaceSize)
        {
            ThrowIfArgument.IsNonpositive(nameof(fraction), fraction, "Fraction is zero or negative.");
            ThrowIfArgument.IsNegative(nameof(dotsCount), dotsCount, "Dots count is negative.");
            ThrowIfArgument.IsNonpositive(nameof(tupletNotesCount), tupletNotesCount, "Tuplet's notes count is zero or negative.");
            ThrowIfArgument.IsNonpositive(nameof(tupletSpaceSize), tupletSpaceSize, "Tuplet's space size is zero or negative.");

            // [1] create simple fraction:
            //     f = 1 / fraction
            //
            // [2] add dots:
            //     f = f * (2 ^ (dotsCount + 1) - 1) / 2 ^ dotsCount
            //
            // [3] make tuplet:
            //     f = f * tupletSpaceSize / tupletNotesCount

            return(new Fraction(((1 << dotsCount + 1) - 1) * tupletSpaceSize,
                                fraction * (1 << dotsCount) * tupletNotesCount));
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Shrinks the current time span by dividing its length by the specified divisor.
        /// </summary>
        /// <param name="divisor">Divisor to shrink the time span by.</param>
        /// <returns>Time span that is the current time span shrinked by the <paramref name="divisor"/>.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="divisor"/> is zero or negative.</exception>
        public ITimeSpan Divide(double divisor)
        {
            ThrowIfArgument.IsNonpositive(nameof(divisor), divisor, "Divisor is zero or negative.");

            return(new MidiTimeSpan(MathUtilities.RoundToLong(TimeSpan / divisor)));
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Shrinks the current time span by dividing its length by the specified divisor.
        /// </summary>
        /// <param name="divisor">Divisor to shrink the time span by.</param>
        /// <returns>Time span that is the current time span shrinked by the <paramref name="divisor"/>.</returns>
        public ITimeSpan Divide(double divisor)
        {
            ThrowIfArgument.IsNonpositive(nameof(divisor), divisor, "Divisor is zero or negative.");

            return(new MetricTimeSpan((long)Math.Round(TotalMicroseconds / divisor)));
        }