Beispiel #1
0
        /// <summary>
        /// Exports the current <see cref="Pattern"/> to track chunk.
        /// </summary>
        /// <param name="tempoMap">Tempo map to process pattern data according with.</param>
        /// <param name="channel">Channel of notes that will be generated by pattern.</param>
        /// <returns>The <see cref="TrackChunk"/> containing notes events generated by the current <see cref="Pattern"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="tempoMap"/> is null.</exception>
        public TrackChunk ToTrackChunk(TempoMap tempoMap, FourBitNumber channel)
        {
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);

            var context = new PatternContext(tempoMap, channel);
            var result  = InvokeActions(0, context);

            //

            var trackChunk = new TrackChunk();

            using (var notesManager = trackChunk.ManageNotes())
            {
                notesManager.Notes.Add(result.Notes ?? Enumerable.Empty <Note>());
            }

            using (var eventsManager = trackChunk.ManageTimedEvents())
            {
                eventsManager.Events.Add(result.Events ?? Enumerable.Empty <TimedEvent>());
            }

            //

            return(trackChunk);
        }
Beispiel #2
0
 public NoteDescriptor(long startTime, long endTime, FourBitNumber channel, SevenBitNumber noteNumber)
 {
     StartTime  = startTime;
     EndTime    = endTime;
     Channel    = channel;
     NoteNumber = noteNumber;
 }
        /// <summary>
        /// Retrieves an instance of the <see cref="Playback"/> for playing MIDI events that will be
        /// produced by specified <see cref="Pattern"/>.
        /// </summary>
        /// <param name="pattern"><see cref="Pattern"/> producing events to play.</param>
        /// <param name="tempoMap">Tempo map used to calculate events times.</param>
        /// <param name="channel">MIDI channel to play channel events on.</param>
        /// <param name="clockSettings">Settings of the internal playback's clock.</param>
        /// <returns>An instance of the <see cref="Playback"/> for playing MIDI events that will be
        /// produced by the <paramref name="pattern"/>.</returns>
        /// <exception cref="ArgumentNullException">
        /// <para>One of the following errors occured:</para>
        /// <list type="bullet">
        /// <item>
        /// <description><paramref name="pattern"/> is <c>null</c>.</description>
        /// </item>
        /// <item>
        /// <description><paramref name="tempoMap"/> is <c>null</c>.</description>
        /// </item>
        /// </list>
        /// </exception>
        public static Playback GetPlayback(this Pattern pattern, TempoMap tempoMap, FourBitNumber channel, MidiClockSettings clockSettings = null)
        {
            ThrowIfArgument.IsNull(nameof(pattern), pattern);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);

            return(pattern.ToTrackChunk(tempoMap, channel).GetPlayback(tempoMap, clockSettings));
        }
Beispiel #4
0
        internal override void Read(MidiReader reader, ReadingSettings settings, int size)
        {
            var data = reader.ReadByte();

            var midiTimeCodeComponent = (byte)data.GetHead();

            if (!Enum.IsDefined(typeof(MidiTimeCodeComponent), midiTimeCodeComponent))
            {
                throw new InvalidMidiTimeCodeComponentException(midiTimeCodeComponent);
            }

            Component = (MidiTimeCodeComponent)midiTimeCodeComponent;

            var componentValue = data.GetTail();

            if (componentValue > ComponentValueMasks[Component])
            {
                switch (settings.InvalidSystemCommonEventParameterValuePolicy)
                {
                case InvalidSystemCommonEventParameterValuePolicy.Abort:
                    throw new InvalidSystemCommonEventParameterValueException(EventType, $"{nameof(ComponentValue)} (component is {Component})", componentValue);

                case InvalidSystemCommonEventParameterValuePolicy.SnapToLimits:
                    componentValue = (FourBitNumber)ComponentValueMasks[Component];
                    break;
                }
            }

            ComponentValue = componentValue;
        }
Beispiel #5
0
        public void TryParse_OutOfRange()
        {
            FourBitNumber result;

            Assert.AreEqual(false, FourBitNumber.TryParse("200", out result));
            Assert.AreEqual(false, FourBitNumber.TryParse("16", out result));
        }
Beispiel #6
0
        private bool TryAddObjectToNewNoteBag(ITimedObject timedObject, ObjectsBuildingSettings settings)
        {
            var bag = new NotesBag();

            if (!bag.TryAddObject(timedObject, null, settings))
            {
                return(false);
            }

            var newNoteTime    = bag.Time;
            var newNoteChannel = bag.NoteId.Channel;

            if (_chordStart < 0)
            {
                _notesBags.Add(bag);
                _chordStart   = newNoteTime;
                _chordChannel = newNoteChannel;
                return(true);
            }
            else
            {
                if (newNoteTime - _chordStart > settings.ChordBuilderSettings.NotesTolerance || newNoteChannel != _chordChannel)
                {
                    _canObjectsBeAdded = !IsCompleted;
                    return(false);
                }

                _notesBags.Add(bag);
                return(true);
            }
        }
Beispiel #7
0
        private void ReactOnUnknownChannelEvent(FourBitNumber statusByte, FourBitNumber channel, MidiReader reader, ReadingSettings settings)
        {
            switch (settings.UnknownChannelEventPolicy)
            {
            case UnknownChannelEventPolicy.Abort:
                throw new UnknownChannelEventException(statusByte, channel);

            case UnknownChannelEventPolicy.SkipStatusByte:
                return;

            case UnknownChannelEventPolicy.SkipStatusByteAndOneDataByte:
                reader.Position += 1;
                return;

            case UnknownChannelEventPolicy.SkipStatusByteAndTwoDataBytes:
                reader.Position += 2;
                return;

            case UnknownChannelEventPolicy.UseCallback:
                var callback = settings.UnknownChannelEventCallback;
                var action   = callback(statusByte, channel);
                switch (action.Instruction)
                {
                case UnknownChannelEventInstruction.Abort:
                    throw new UnknownChannelEventException(statusByte, channel);

                case UnknownChannelEventInstruction.SkipData:
                    reader.Position += action.DataBytesToSkip;
                    return;
                }
                break;
            }
        }
Beispiel #8
0
        /// <summary>
        /// Retrieves an instance of the <see cref="Playback"/> for playing MIDI events that will be
        /// produced by specified <see cref="Pattern"/>.
        /// </summary>
        /// <param name="pattern"><see cref="Pattern"/> producing events to play.</param>
        /// <param name="tempoMap">Tempo map used to calculate events times.</param>
        /// <param name="channel">MIDI channel to play channel events on.</param>
        /// <param name="outputDevice">Output MIDI device to play events through.</param>
        /// <returns>An instance of the <see cref="Playback"/> for playing MIDI events that will be
        /// produced by the <paramref name="pattern"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="pattern"/> is null. -or-
        /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
        public static Playback GetPlayback(this Pattern pattern, TempoMap tempoMap, FourBitNumber channel, OutputDevice outputDevice)
        {
            ThrowIfArgument.IsNull(nameof(pattern), pattern);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);

            return(pattern.ToTrackChunk(tempoMap, channel).GetPlayback(tempoMap, outputDevice));
        }
Beispiel #9
0
        private static bool IsAppropriateNoteOnTimedEvent(TimedEvent timedEvent, FourBitNumber channel, SevenBitNumber noteNumber)
        {
            var noteOnEvent = timedEvent.Event as NoteOnEvent;

            return(noteOnEvent != null &&
                   noteOnEvent.Channel == channel &&
                   noteOnEvent.NoteNumber == noteNumber);
        }
        /// <summary>
        /// Plays MIDI events that will be produced by specified <see cref="Pattern"/>.
        /// </summary>
        /// <param name="pattern"><see cref="Pattern"/> producing events to play.</param>
        /// <param name="tempoMap">Tempo map used to calculate events times.</param>
        /// <param name="channel">MIDI channel to play channel events on.</param>
        /// <param name="outputDevice">Output MIDI device to play events through.</param>
        /// <param name="clockSettings">Settings of the internal playback's clock.</param>
        /// <exception cref="ArgumentNullException">
        /// <para>One of the following errors occured:</para>
        /// <list type="bullet">
        /// <item>
        /// <description><paramref name="pattern"/> is <c>null</c>.</description>
        /// </item>
        /// <item>
        /// <description><paramref name="tempoMap"/> is <c>null</c>.</description>
        /// </item>
        /// <item>
        /// <description><paramref name="outputDevice"/> is <c>null</c>.</description>
        /// </item>
        /// </list>
        /// </exception>
        public static void Play(this Pattern pattern, TempoMap tempoMap, FourBitNumber channel, IOutputDevice outputDevice, MidiClockSettings clockSettings = null)
        {
            ThrowIfArgument.IsNull(nameof(pattern), pattern);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);

            pattern.ToTrackChunk(tempoMap, channel).Play(tempoMap, outputDevice, clockSettings);
        }
Beispiel #11
0
 public NotePlaybackData(SevenBitNumber noteNumber, SevenBitNumber velocity, SevenBitNumber offVelocity, FourBitNumber channel)
     : this(true)
 {
     NoteNumber  = noteNumber;
     Velocity    = velocity;
     OffVelocity = offVelocity;
     Channel     = channel;
 }
Beispiel #12
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>
        /// <param name="channel">Channel an event should be created 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, FourBitNumber channel)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(program), program);

            return(new ProgramChangeEvent(program.AsSevenBitNumber())
            {
                Channel = channel
            });
        }
Beispiel #13
0
        /// <summary>
        /// Gets the play times of notes associated with the selected instrument.
        /// </summary>
        /// <param name="instrument">Instrument to retrieve note times for.</param>
        /// <returns>Note times for instrument.</returns>
        public List <long> RetrieveNoteTimesForInstrument(FourBitNumber instrument)
        {
            var midiMap = this.midi.GetTempoMap();

            return(this.midi.GetNotes()
                   .Where(note => note.Channel == instrument)
                   .Select(note => ((MetricTimeSpan)note.TimeAs(TimeSpanType.Metric, midiMap)).TotalMicroseconds / 1000)
                   .Distinct()
                   .ToList());
        }
Beispiel #14
0
        /// <summary>
        /// Exports the current <see cref="Pattern"/> to track chunk.
        /// </summary>
        /// <param name="tempoMap">Tempo map to process pattern data according with.</param>
        /// <param name="channel">Channel of notes that will be generated by pattern.</param>
        /// <returns>The <see cref="TrackChunk"/> containing notes events generated by the current <see cref="Pattern"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="tempoMap"/> is <c>null</c>.</exception>
        public TrackChunk ToTrackChunk(TempoMap tempoMap, FourBitNumber channel)
        {
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);

            var context = new PatternContext(tempoMap, channel);
            var result  = InvokeActions(0, context);

            return(((IEnumerable <ITimedObject>)result.Events ?? Enumerable.Empty <TimedEvent>())
                   .Concat(result.Notes ?? Enumerable.Empty <Note>())
                   .ToTrackChunk());
        }
Beispiel #15
0
        /// <summary>
        /// Exports the current <see cref="Pattern"/> to MIDI file.
        /// </summary>
        /// <param name="tempoMap">Tempo map to process pattern data according with.</param>
        /// <param name="channel">Channel of notes that will be generated by pattern.</param>
        /// <returns>The <see cref="MidiFile"/> containing notes events generated by the current <see cref="Pattern"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="tempoMap"/> is null.</exception>
        public MidiFile ToFile(TempoMap tempoMap, FourBitNumber channel)
        {
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);

            var trackChunk = ToTrackChunk(tempoMap, channel);

            var midiFile = new MidiFile(trackChunk);

            midiFile.ReplaceTempoMap(tempoMap);

            return(midiFile);
        }
        public void TryParse()
        {
            FourBitNumber result;

            FourBitNumber.TryParse("12", out result);
            Assert.AreEqual((FourBitNumber)12, result);

            FourBitNumber.TryParse("0", out result);
            Assert.AreEqual((FourBitNumber)0, result);

            FourBitNumber.TryParse("15", out result);
            Assert.AreEqual((FourBitNumber)15, result);
        }
Beispiel #17
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MidiTimeCodeEvent"/> with the specified
        /// time code component and its value.
        /// </summary>
        /// <param name="component">MIDI time code component.</param>
        /// <param name="componentValue">Value of <paramref name="component"/>.</param>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="component"/> specified an
        /// invalid value.</exception>
        public MidiTimeCodeEvent(MidiTimeCodeComponent component, FourBitNumber componentValue)
            : this()
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(component), component);

            var maximumComponentValue = ComponentValueMasks[component];

            ThrowIfArgument.IsGreaterThan(nameof(componentValue),
                                          componentValue,
                                          maximumComponentValue,
                                          $"Component's value is greater than maximum valid one which is {maximumComponentValue}.");

            Component      = component;
            ComponentValue = componentValue;
        }
Beispiel #18
0
        private IEnumerable <Note> CreateNotes(string[] timesAndLengths,
                                               SevenBitNumber noteNumber,
                                               FourBitNumber channel,
                                               TempoMap tempoMap)
        {
            var notes = ObjectMethods.CreateCollection(tempoMap, timesAndLengths);

            foreach (var note in notes)
            {
                note.NoteNumber = noteNumber;
                note.Channel    = channel;
            }

            return(notes);
        }
Beispiel #19
0
    private static int?GetProgramNumber(FourBitNumber channel, long time, Dictionary <FourBitNumber, Dictionary <long, SevenBitNumber> > programChanges)
    {
        Dictionary <long, SevenBitNumber> changes;

        if (!programChanges.TryGetValue(channel, out changes))
        {
            return(null);
        }

        var times = changes.Keys.Where(t => t <= time).ToArray();

        return(times.Any()
            ? (int?)changes[times.Max()]
            : null);
    }
Beispiel #20
0
        public static void ParseAndPlay(string text,
                                        string nameSynth = null)
        {
            if (nameSynth == null)
            {
                //    nameSynth = "Microsoft GS Wavetable Synth";
                var devices = AllDevices();
                nameSynth = devices[R.Next(0, devices.Length)];
            }

            var g = Enum.GetValues(typeof(NoteName));

            T2MJsonObject obj = null;

            obj = JsonConvert.DeserializeObject <T2MJsonObject>(text);


            var midiFile = new MidiFile();
            var cmdsplit = "-".ToCharArray();

#if DEBUG
            StringBuilder sb = new StringBuilder();
#endif

            foreach (MidiTrack track in obj.Tracks)
            {
                FourBitNumber channel  = (FourBitNumber)(track.Channel & 15);
                int           velocity = track.Velocity;
                var           instro   = new ProgramChangeEvent((SevenBitNumber)track.Instrument);
                instro.Channel = channel;
                var trackChunk = new TrackChunk(instro);
#if DEBUG
                sb.Append("Begin of Chunk" + Environment.NewLine);
#endif

                int length = 40;
                using (var cm = trackChunk.ManageChords())
                {
                    ChordsCollection chords = cm.Chords;

                    var commands = string.Join(" ", track.Commands).Split(' ', '\t', '\r', '\n');

                    //   NoteName tpz = (NoteName)_EXT_.AllNotes.GetValue(0); // TODO Transpose as cmd


                    int    t   = track.Start;
                    int    i   = track.Interval;
                    int    oct = track.Octave;
                    string cmd;

                    foreach (string v in commands)
                    {
                        if (v.StartsWith("/"))
                        {
                            cmd = v.TrimStart('/');
                            if (cmd == "_")
                            {
                                t += i; continue;
                            }
                            var n0 = cmd.Split(cmdsplit, StringSplitOptions.RemoveEmptyEntries).Select(x => GetNoteName(x));

                            var nn = n0; //.FromTemplate(n0);
                                         //   nn = nn.FromTemplate(tpz);

#if DEBUG
                            var m = string.Join(" ",
                                                nn.Select(x => x.Name.ToString().Replace("Sharp", "#") +
                                                          " " + (x.Octave == -1 ? oct : x.Octave)));

                            sb.Append(m + " /");
                            sb.Append(Environment.NewLine);
#endif

                            InterNote[] ni = nn.Select(x => new InterNote(x.Name, x.Octave == -1 ? oct : x.Octave, length, t)
                            {
                                Channel  = channel,
                                Velocity = (SevenBitNumber)(velocity & 127)
                            })
                                             //  .Concat(new[] { new InterNote(nn.First(), oct + 1, G, t) })
                                             .ToArray();

                            var chord = new IA.Chord(ni);
                            chords.Add(chord);
                            t += i;
                        }
                        else
                        if (v.StartsWith("*"))
                        {
                            cmd = v.TrimStart('*');
                            if (int.TryParse(cmd, out int ia))
                            {
                                oct = ia;
                            }
                        }
                        else
                        if (v.StartsWith("+"))
                        {
                            cmd = v.TrimStart('+');
                            if (int.TryParse(cmd, out int ia))
                            {
                                i += ia;
                            }
                        }
                        else
                        if (v.StartsWith("-"))
                        {
                            if (int.TryParse(v, out int ia))
                            {
                                i += ia;
                            }
                        }
                        else
                        if (v.StartsWith("L"))
                        {
                            cmd = v.TrimStart('L');
                            if (int.TryParse(cmd, out int ia))
                            {
                                length = ia;
                            }
                        }
                        else
                        if (v == "_")
                        {
                            t += i; continue;
                        }
                    }

                    cm.SaveChanges();
                }

                midiFile.Chunks.Add(trackChunk);
#if DEBUG
                sb.Append(Environment.NewLine);
                sb.Append("End of Chunk");
                sb.Append(Environment.NewLine);
#endif
            }

            var appDir = Assembly.GetExecutingAssembly().Location;
            appDir = Path.GetDirectoryName(appDir);
            var file = "Im3" + DateTime.Now.ToString("yyyy-MM-dd--HH-mm-ss") + ".mid";
            file = Path.Combine(appDir, file);
            midiFile.Write(file);
            Process.Start(appDir);

#if DEBUG
            var file2 = file + ".txt";
            file2 = Path.Combine(appDir, file2);
            File.WriteAllText(file2, sb.ToString());
            Process.Start(file2);
#endif

            using (var outputDevice = OutputDevice.GetByName(nameSynth))
                using (var playback = midiFile.GetPlayback(outputDevice))
                {
                    // playback.Speed = 2.0;
                    playback.Play();
                }
        }
        /// <summary>
        /// Gets MIDI events sequence to switch to the specified General MIDI Level 2 program.
        /// </summary>
        /// <param name="program"><see cref="GeneralMidi2Program"/> to get events for.</param>
        /// <param name="channel">Channel events should be created for.</param>
        /// <returns>MIDI events sequence to switch to the <paramref name="program"/>.</returns>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="program"/> specified an invalid value.</exception>
        public static IEnumerable <MidiEvent> GetProgramEvents(this GeneralMidi2Program program, FourBitNumber channel)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(program), program);

            var programData = ProgramsData[program];

            return(new[]
            {
                ControlName.BankSelect.GetControlChangeEvent(programData.BankMsb, channel),
                ControlName.LsbForBankSelect.GetControlChangeEvent(programData.BankLsb, channel),
                programData.GeneralMidiProgram.GetProgramEvent(channel)
            });
        }
 public void TryParse_InvalidFormat()
 {
     Assert.AreEqual(false, FourBitNumber.TryParse("sdsd", out _));
 }
 public void Parse()
 {
     Assert.AreEqual((FourBitNumber)12, FourBitNumber.Parse("12"));
     Assert.AreEqual((FourBitNumber)0, FourBitNumber.Parse("0"));
     Assert.AreEqual((FourBitNumber)15, FourBitNumber.Parse("15"));
 }
 public void Parse_OutOfRange()
 {
     Assert.Throws <FormatException>(() => FourBitNumber.Parse("200"));
     Assert.Throws <FormatException>(() => FourBitNumber.Parse("16"));
 }
 public void Parse_InvalidFormat()
 {
     Assert.Throws <FormatException>(() => FourBitNumber.Parse("sdsd"));
 }
 public static byte Combine(FourBitNumber head, FourBitNumber tail)
 {
     return((byte)((head << 4) | tail));
 }
Beispiel #27
0
 public static byte TrackType(FourBitNumber channel)
 {
     return(TrackType((byte)channel));
 }
Beispiel #28
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>
        /// <param name="channel">Channel an event should be created for.</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, FourBitNumber channel)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(controlName), controlName);

            return(new ControlChangeEvent(controlName.AsSevenBitNumber(), controlValue)
            {
                Channel = channel
            });
        }
 public PatternContext(TempoMap tempoMap, FourBitNumber channel)
 {
     TempoMap = tempoMap;
     Channel  = channel;
 }
Beispiel #30
0
 /// <summary>
 /// Initializes a new instance of the <see cref="NoteId"/> class.
 /// </summary>
 /// <param name="channel">The audio channel associated with the musical note.</param>
 /// <param name="noteNumber">The identification number associated with the musical note.</param>
 public NoteId(FourBitNumber channel, SevenBitNumber noteNumber)
 {
     Channel    = channel;
     NoteNumber = noteNumber;
 }