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); }
/// <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); }
/// <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); }
/// <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."); }
/// <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]); }
/// <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())); }
/// <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); }
/// <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); }
/// <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)); }
/// <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)); }
/// <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)); }
/// <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)); }
/// <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; }
internal static ITimeSpan Subtract(ITimeSpan timeSpan1, ITimeSpan timeSpan2, TimeSpanMode mode) { ThrowIfArgument.IsInvalidEnumValue(nameof(mode), mode); return(new MathTimeSpan(timeSpan1, timeSpan2, MathOperation.Subtract, mode)); }
/// <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); }