Beispiel #1
0
        /// <summary>
        /// Starts a tick generator.
        /// </summary>
        /// <param name="interval">Interval between ticks.</param>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="interval"/> is out of
        /// [<see cref="MinInterval"/>; <see cref="MaxInterval"/>] range.</exception>
        protected override void Start(TimeSpan interval)
        {
            ThrowIfArgument.IsOutOfRange(nameof(interval),
                                         interval,
                                         MinInterval,
                                         MaxInterval,
                                         $"Interval is out of [{MinInterval}, {MaxInterval}] range.");

            var intervalInMilliseconds = (uint)interval.TotalMilliseconds;

            var timeCaps = default(MidiTimerWinApi.TIMECAPS);

            ProcessMmResult(MidiTimerWinApi.timeGetDevCaps(ref timeCaps, (uint)Marshal.SizeOf(timeCaps)));

            _resolution   = Math.Min(Math.Max(timeCaps.wPeriodMin, intervalInMilliseconds), timeCaps.wPeriodMax);
            _tickCallback = OnTick;

            ProcessMmResult(MidiTimerWinApi.timeBeginPeriod(_resolution));
            _timerId = MidiTimerWinApi.timeSetEvent(intervalInMilliseconds, _resolution, _tickCallback, IntPtr.Zero, MidiTimerWinApi.TIME_PERIODIC);
            if (_timerId == NoTimerId)
            {
                var errorCode = Marshal.GetLastWin32Error();
                throw new MidiDeviceException("Unable to start tick generator.", new Win32Exception(errorCode));
            }
        }
        /// <summary>
        /// Splits objects by the specified ratio of an object's length measuring it from
        /// the object's start or end. For example, 0.5 means splitting at the center of an object.
        /// </summary>
        /// <param name="objects">Objects to split.</param>
        /// <param name="ratio">Ratio of an object's length to split by. Valid values are from 0 to 1.</param>
        /// <param name="lengthType">The type an object's length should be processed according to.</param>
        /// <param name="from">Point of an object distance should be measured from.</param>
        /// <param name="tempoMap">Tempo map used for distances calculations.</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="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 IEnumerable <TObject> SplitAtDistance(IEnumerable <TObject> objects, double ratio, TimeSpanType lengthType, LengthedObjectTarget from, TempoMap tempoMap)
        {
            ThrowIfArgument.IsNull(nameof(objects), objects);
            ThrowIfArgument.IsOutOfRange(nameof(ratio),
                                         ratio,
                                         ZeroRatio,
                                         FullLengthRatio,
                                         $"Ratio is out of [{ZeroRatio}; {FullLengthRatio}] range.");
            ThrowIfArgument.IsInvalidEnumValue(nameof(lengthType), lengthType);
            ThrowIfArgument.IsInvalidEnumValue(nameof(from), from);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);

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

                    continue;
                }

                var distance = obj.LengthAs(lengthType, tempoMap).Multiply(ratio);
                var parts    = SplitObjectAtDistance(obj, distance, from, tempoMap);

                if (parts.LeftPart != null)
                {
                    yield return(parts.LeftPart);
                }

                if (parts.RightPart != null)
                {
                    yield return(parts.RightPart);
                }
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="HighPrecisionTickGenerator"/> with the specified
        /// interval.
        /// </summary>
        /// <param name="interval">Interval of ticking.</param>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="interval"/> is out of valid range.</exception>
        public HighPrecisionTickGenerator(TimeSpan interval)
        {
            ThrowIfArgument.IsOutOfRange(nameof(interval),
                                         interval,
                                         MinInterval,
                                         MaxInterval,
                                         $"Interval is out of [{MinInterval}, {MaxInterval}] range.");

            _interval = (uint)interval.TotalMilliseconds;
        }
Beispiel #4
0
        /// <summary>
        /// Returns an <see cref="Interval"/> by the specified signed number of
        /// half steps where negative one means downward interval.
        /// </summary>
        /// <param name="halfSteps">The number of half steps.</param>
        /// <returns>An <see cref="Interval"/> represented by the <paramref name="halfSteps"/>.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="halfSteps"/> is out of range
        /// (result interval is out of the [-127,127] range).</exception>
        public static Interval FromHalfSteps(int halfSteps)
        {
            ThrowIfArgument.IsOutOfRange(nameof(halfSteps),
                                         halfSteps,
                                         -SevenBitNumber.MaxValue,
                                         SevenBitNumber.MaxValue,
                                         "Half steps number is out of range.");

            return(Get((SevenBitNumber)Math.Abs(halfSteps),
                       Math.Sign(halfSteps) < 0 ? IntervalDirection.Down : IntervalDirection.Up));
        }
Beispiel #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RegularPrecisionTickGenerator"/> with the specified
        /// interval.
        /// </summary>
        /// <param name="interval">Interval of ticking.</param>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="interval"/> is out of valid range.</exception>
        public RegularPrecisionTickGenerator(TimeSpan interval)
        {
            ThrowIfArgument.IsOutOfRange(nameof(interval),
                                         interval,
                                         MinInterval,
                                         MaxInterval,
                                         $"Interval is out of [{MinInterval}, {MaxInterval}] range.");

            _timer          = new Timer(interval.TotalMilliseconds);
            _timer.Elapsed += OnElapsed;
        }
Beispiel #6
0
        /// <summary>
        /// Moves to the nth anchor.
        /// </summary>
        /// <param name="index">Index of an anchor to move to.</param>
        /// <returns>The current <see cref="PatternBuilder"/>.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is out of range.</exception>
        public PatternBuilder MoveToNthAnchor(int index)
        {
            var counter = GetAnchorCounter(null);

            ThrowIfArgument.IsOutOfRange(nameof(index),
                                         index,
                                         0,
                                         counter - 1,
                                         "Index is out of range.");

            return(AddAction(new MoveToAnchorAction(AnchorPosition.Nth, index)));
        }
        /// <summary>
        /// Starts a tick generator.
        /// </summary>
        /// <param name="interval">Interval between ticks.</param>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="interval"/> is out of
        /// [<see cref="MinInterval"/>; <see cref="MaxInterval"/>] range.</exception>
        protected override void Start(TimeSpan interval)
        {
            ThrowIfArgument.IsOutOfRange(nameof(interval),
                                         interval,
                                         MinInterval,
                                         MaxInterval,
                                         $"Interval is out of [{MinInterval}, {MaxInterval}] range.");

            _timer          = new Timer(interval.TotalMilliseconds);
            _timer.Elapsed += OnElapsed;
            _timer.Start();
        }
        /// <summary>
        /// Converts sub-array of the specified bytes to an instance of the <see cref="MidiEvent"/>.
        /// </summary>
        /// <param name="bytes">Bytes to take sub-array from.</param>
        /// <param name="offset">Offset of sub-array to read MIDI event from.</param>
        /// <param name="length">Length of sub-array to read MIDI event from.</param>
        /// <returns><see cref="MidiEvent"/> read from <paramref name="bytes"/> starting from
        /// <paramref name="offset"/> and taking <paramref name="length"/> of bytes.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="bytes"/> is null.</exception>
        /// <exception cref="ArgumentException"><paramref name="bytes"/> is an empty array.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="offset"/> is out of range. -or-
        /// <paramref name="length"/> is out of range.</exception>
        public MidiEvent Convert(byte[] bytes, int offset, int length)
        {
            ThrowIfArgument.IsNull(nameof(bytes), bytes);
            ThrowIfArgument.IsEmptyCollection(nameof(bytes), bytes, "Bytes is empty array.");
            ThrowIfArgument.IsOutOfRange(nameof(offset), offset, 0, bytes.Length - 1, "Offset is out of range.");
            ThrowIfArgument.IsOutOfRange(nameof(length), length, 0, bytes.Length - offset, "Length is out of range.");

            var dataBytes = new byte[bytes.Length - 1 - offset];

            Array.Copy(bytes, offset + 1, dataBytes, 0, dataBytes.Length);

            return(Convert(bytes[offset], dataBytes));
        }
Beispiel #9
0
        /// <summary>
        /// Splits notes contained in the specified <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="trackChunk"><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="trackChunk"/> 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 TrackChunk trackChunk, double ratio, TimeSpanType lengthType, LengthedObjectTarget from, TempoMap tempoMap)
        {
            ThrowIfArgument.IsNull(nameof(trackChunk), trackChunk);
            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);

            SplitTrackChunkNotes(trackChunk, (splitter, notes) => splitter.SplitAtDistance(notes, ratio, lengthType, from, tempoMap));
        }
Beispiel #10
0
        /// <summary>
        /// Splits chords contained in the specified <see cref="TrackChunk"/> by the specified ratio of a
        /// chord's length measuring it from the chord's start or end. For example, 0.5 means splitting
        /// at the center of a chord.
        /// </summary>
        /// <param name="trackChunk"><see cref="TrackChunk"/> to split chords in.</param>
        /// <param name="ratio">Ratio of a chord's length to split by. Valid values are from 0 to 1.</param>
        /// <param name="lengthType">The type a chord's length should be processed according to.</param>
        /// <param name="from">Point of a chord distance should be measured from.</param>
        /// <param name="tempoMap">Tempo map used for distances calculations.</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="ratio"/> is out of valid range.</exception>
        /// <exception cref="InvalidEnumArgumentException">
        /// <para>One of the following errors occured:</para>
        /// <list type="bullet">
        /// <item>
        /// <description><paramref name="lengthType"/> specified an invalid value.</description>
        /// </item>
        /// <item>
        /// <description><paramref name="from"/> specified an invalid value.</description>
        /// </item>
        /// </list>
        /// </exception>
        public static void SplitChordsAtDistance(this TrackChunk trackChunk, double ratio, TimeSpanType lengthType, LengthedObjectTarget from, TempoMap tempoMap, ChordDetectionSettings settings = null)
        {
            ThrowIfArgument.IsNull(nameof(trackChunk), trackChunk);
            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);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);

            SplitTrackChunkChords(trackChunk, (splitter, chords) => splitter.SplitAtDistance(chords, ratio, lengthType, from, tempoMap), settings);
        }
Beispiel #11
0
        /// <summary>
        /// Splits notes contained in the specified <see cref="MidiFile"/> 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="midiFile"><see cref="MidiFile"/> 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>
        /// <exception cref="ArgumentNullException"><paramref name="midiFile"/> 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 MidiFile midiFile, double ratio, TimeSpanType lengthType, LengthedObjectTarget from)
        {
            ThrowIfArgument.IsNull(nameof(midiFile), midiFile);
            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);

            var tempoMap = midiFile.GetTempoMap();

            midiFile.GetTrackChunks().SplitNotesAtDistance(ratio, lengthType, from, tempoMap);
        }
Beispiel #12
0
        /// <summary>
        /// Gets an octave by the specified octave number.
        /// </summary>
        /// <param name="octaveNumber">The number of an octave.</param>
        /// <returns>An octave with the specified number.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="octaveNumber"/> is out of valid range.</exception>
        public static Octave Get(int octaveNumber)
        {
            ThrowIfArgument.IsOutOfRange(nameof(octaveNumber),
                                         octaveNumber,
                                         MinOctaveNumber,
                                         MaxOctaveNumber,
                                         $"Octave number is out of [{MinOctaveNumber}, {MaxOctaveNumber}] range.");

            Octave octave;

            if (!_cache.TryGetValue(octaveNumber, out octave))
            {
                _cache.Add(octaveNumber, octave = new Octave(octaveNumber));
            }

            return(octave);
        }
Beispiel #13
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);
            }
        }
Beispiel #14
0
        /// <summary>
        /// Gets an octave definition by the specified octave number.
        /// </summary>
        /// <param name="octave">The number of an octave.</param>
        /// <returns>A definition of the octave with the specified number.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="octave"/> is out of valid range.</exception>
        public static OctaveDefinition Get(int octave)
        {
            ThrowIfArgument.IsOutOfRange(nameof(octave),
                                         octave,
                                         MinOctaveNumber,
                                         MaxOctaveNumber,
                                         $"Octave number is out of [{MinOctaveNumber}, {MaxOctaveNumber}] range.");

            OctaveDefinition octaveDefinition;

            if (!_cache.TryGetValue(octave, out octaveDefinition))
            {
                _cache.Add(octave, octaveDefinition = new OctaveDefinition(octave));
            }

            return(octaveDefinition);
        }
        /// <summary>
        /// Retrieves output MIDI device with the specified ID.
        /// </summary>
        /// <param name="id">Device ID which is number from 0 to <see cref="GetDevicesCount"/> minus 1.</param>
        /// <returns>Output MIDI device with the specified ID.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="id"/> is out of valid range.</exception>
        public static OutputDevice GetById(int id)
        {
            ThrowIfArgument.IsOutOfRange(nameof(id), id, 0, GetDevicesCount() - 1, "Device ID is out of range.");

            return(new OutputDevice(id));
        }
Beispiel #16
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SevenBitNumber"/> with the specified value.
        /// </summary>
        /// <param name="value">Value representing seven-bit number.</param>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="value"/> is out of
        /// [<see cref="MinValue"/>; <see cref="MaxValue"/>] range.</exception>
        public SevenBitNumber(byte value)
        {
            ThrowIfArgument.IsOutOfRange(nameof(value), value, Min, Max, "Value is out of range valid for seven-bit number.");

            _value = value;
        }