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
        private static void SingleTrack(string filename)
        {
            // We open the file...
            var f = MidiFile.Read(filename);

            // Then we convert all the events to absolute time and merge them together
            var merged = new TrackChunk();

            using (var mergedTimedEvents = merged.ManageTimedEvents())
            {
                foreach (var chunk in f.GetTrackChunks())
                {
                    using var m = chunk.ManageTimedEvents();
                    mergedTimedEvents.Events.Add(m.Events);
                }
                mergedTimedEvents.SaveChanges();
            }

            // And save
            var outFile = new MidiFile {
                TimeDivision = f.TimeDivision, Chunks = { merged }
            };

            outFile.Write(Path.Join(
                              Path.GetDirectoryName(filename),
                              $"{Path.GetFileNameWithoutExtension(filename)}.singletrack.mid"),
                          overwriteFile: true,
                          format: MidiFileFormat.SingleTrack);
        }
Beispiel #3
0
        /// <summary>
        /// Randomizes timed events contained in the specified <see cref="TrackChunk"/>.
        /// </summary>
        /// <param name="trackChunk"><see cref="TrackChunk"/> to randomize timed events in.</param>
        /// <param name="bounds">Bounds to randomize time within.</param>
        /// <param name="tempoMap">Tempo map used to calculate time bounds to randomize within.</param>
        /// <param name="settings">Settings according to which timed events should be randomized.</param>
        /// <exception cref="ArgumentNullException"><paramref name="trackChunk"/> is null. -or-
        /// <paramref name="bounds"/> is null. -or- <paramref name="tempoMap"/> is null.</exception>
        public static void RandomizeTimedEvents(this TrackChunk trackChunk, IBounds bounds, TempoMap tempoMap, TimedEventsRandomizingSettings settings = null)
        {
            ThrowIfArgument.IsNull(nameof(trackChunk), trackChunk);
            ThrowIfArgument.IsNull(nameof(bounds), bounds);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);

            using (var timedEventsManager = trackChunk.ManageTimedEvents())
            {
                new TimedEventsRandomizer().Randomize(timedEventsManager.Events, bounds, tempoMap, settings);
            }
        }
        /// <summary>
        /// Quantizes timed events contained in the specified <see cref="TrackChunk"/>.
        /// </summary>
        /// <param name="trackChunk"><see cref="TrackChunk"/> to quantize timed events in.</param>
        /// <param name="grid">Grid to quantize objects by.</param>
        /// <param name="tempoMap">Tempo map used to calculate times to quantize by.</param>
        /// <param name="settings">Settings according to which timed events should be quantized.</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="grid"/> is <c>null</c>.</description>
        /// </item>
        /// <item>
        /// <description><paramref name="tempoMap"/> is <c>null</c>.</description>
        /// </item>
        /// </list>
        /// </exception>
        public static void QuantizeTimedEvents(this TrackChunk trackChunk, IGrid grid, TempoMap tempoMap, TimedEventsQuantizingSettings settings = null)
        {
            ThrowIfArgument.IsNull(nameof(trackChunk), trackChunk);
            ThrowIfArgument.IsNull(nameof(grid), grid);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);

            using (var timedEventsManager = trackChunk.ManageTimedEvents())
            {
                new TimedEventsQuantizer().Quantize(timedEventsManager.Events, grid, tempoMap, settings);
            }
        }
Beispiel #5
0
        static void Split(string filename)
        {
            // We open the file...
            var f = MidiFile.Read(filename);

            // We create channel handlers for each channel in the file...
            var channels = f.GetChannels().ToDictionary(
                x => x,
                x => new ChannelHandler(x));

            // Then we parse the file and filter into these handlers
            var merged = new TrackChunk();

            using (var mergedTimedEvents = merged.ManageTimedEvents())
            {
                foreach (var chunk in f.GetTrackChunks())
                {
                    Console.WriteLine($"Adding {chunk.Events.Count} events from chunk...");
                    using var m = chunk.ManageTimedEvents();
                    mergedTimedEvents.Events.Add(m.Events);
                }
                mergedTimedEvents.SaveChanges();
                Console.WriteLine($"Total events is now {mergedTimedEvents.Events.Count()}, length = {(TimeSpan)mergedTimedEvents.Events.Last().TimeAs<MetricTimeSpan>(f.GetTempoMap())}");
            }

            var maxTime = merged.Events.Sum(x => x.DeltaTime);

            Console.WriteLine($"Total {merged.Events.Count} events, time {maxTime} = {(TimeSpan)TimeConverter.ConvertTo<MetricTimeSpan>(maxTime, f.GetTempoMap())}");

            foreach (var e in merged.Events)
            {
                // Pass everything else through to all channels handlers
                foreach (var channelHandler in channels.Values)
                {
                    channelHandler.Write(e);
                }
            }

            // Then pad them all to the same length
            var maxLength = channels.Values.Max(x => x.GetMaxLength());

            foreach (var writer in channels.Values)
            {
                writer.WriteToDisk(
                    maxLength,
                    Path.Combine(
                        Path.GetDirectoryName(filename) ?? "",
                        Path.GetFileNameWithoutExtension(filename)),
                    f.TimeDivision);
            }
        }
Beispiel #6
0
            private static MidiFile CreateTestFile()
            {
                const int trackChunksNumber   = 10;
                const int eventsPerTrackChunk = 10000;

                var midiFile = new MidiFile();

                for (int i = 0; i < trackChunksNumber; i++)
                {
                    var trackChunk = new TrackChunk();

                    using (var timedEventsManager = trackChunk.ManageTimedEvents())
                    {
                        for (int j = 0; j < eventsPerTrackChunk; j++)
                        {
                            timedEventsManager.Events.Add(new TimedEvent(new SetTempoEvent(j + 1), j));
                        }
                    }

                    midiFile.Chunks.Add(trackChunk);
                }

                return(midiFile);
            }
Beispiel #7
0
        private void btnSave_Click(object sender, EventArgs e)
        {
            if (Path.GetExtension(filePath) == ".mid")
            {
                var chunks      = song.GetTrackChunks().ToArray();
                var tempoMap    = song.GetTempoMap();
                var fixedMidi   = new MidiFile();
                var headerChunk = new TrackChunk();

                int i       = 0;
                var t0Notes = chunks[0].GetNotes().ToArray();
                if (t0Notes.Length == 0)    // check if there are notes in Track0
                {
                    i = 1;
                    var timedEvents = chunks[0].GetTimedEvents().ToArray();
                    var title       = timedEvents.Where(t => t.Event.EventType == MidiEventType.SequenceTrackName);
                    if (title.Count() == 1)
                    {
                        headerChunk.AddTimedEvents(title);
                    }
                }

                fixedMidi.Chunks.Add(headerChunk);
                fixedMidi.ReplaceTempoMap(tempoMap);

                for (int ch = 0; i < chunks.Count(); i++, ch++)
                {
                    var newChunk    = new TrackChunk();
                    var timedEvents = chunks[i].GetTimedEvents();

                    using (var timedEventsManager = newChunk.ManageTimedEvents())
                    {
                        foreach (var timedEvent in timedEvents)
                        {
                            var eventType = timedEvent.Event.EventType;
                            if (eventType == MidiEventType.SequenceTrackName)
                            {
                                timedEventsManager.Events.Add(timedEvent);
                            }
                            else if (eventType == MidiEventType.ProgramChange)
                            {
                                var pcEvent = timedEvent.Event as ProgramChangeEvent;
                                pcEvent.Channel = (FourBitNumber)ch;
                                timedEventsManager.Events.AddEvent(pcEvent, timedEvent.Time);
                            }
                        }
                    }

                    using (var notesManager = newChunk.ManageNotes())
                    {
                        var notes = chunks[i].GetNotes().ToArray();
                        foreach (var n in notes)
                        {
                            var newNote = n;
                            newNote.Channel = (FourBitNumber)ch;   // change channel of the notes in track
                            notesManager.Notes.Add(newNote);
                        }
                    }

                    fixedMidi.Chunks.Add(newChunk);
                }

                string outputFilename = Path.GetFileNameWithoutExtension(filePath) + "_fix.mid";
                WriteMidiToFile(fixedMidi, outputFilename);
                textBox1.AppendText("Wrote to file: " + outputFilename + Environment.NewLine);
            }
            else if (Path.GetExtension(filePath) == ".mml")
            {
                string outputFilename = Path.GetFileNameWithoutExtension(filePath) + "_fix.mml";
                File.WriteAllText(outputFilename, sb.ToString());
                textBox1.AppendText("Wrote to file: " + outputFilename + Environment.NewLine);
            }
        }
Beispiel #8
0
    void _ParseAuthoring()
    {
        _authoring.Clear();

        if (!_HasMidiFile())
        {
            return;
        }

        TrackChunk authTrack = _FindAuthoringTracks();

        if (authTrack == null)
        {
            return;
        }

        using (TimedEventsManager timedEventsManager = authTrack.ManageTimedEvents())
        {
            // Get timed events ordered by time
            TimedEventsCollection events = timedEventsManager.Events;

            AuthoringEvent newEvent = null;
            int            curNote  = -1;
            foreach (var midiEvent in events)
            {
                if (!(midiEvent.Event is SequenceTrackNameEvent) && !(midiEvent.Event is BaseTextEvent) && (midiEvent.Event is NoteOnEvent)) //ignore text events!
                {
                    newEvent         = new AuthoringEvent();
                    curNote          = (midiEvent.Event as NoteOnEvent).NoteNumber;
                    newEvent.NoteIdx = curNote - BaseInstrumentNote;

                    if (newEvent.NoteIdx < 0) //note was less than our BaseInstrumentNote, so ignore!
                    {
                        continue;
                    }

                    float startSecs = midiEvent.TimeAs <MetricTimeSpan>(_tempoMap).TotalMicroseconds / 1000000.0f;
                    newEvent.NoteOnBeat = SecsToBeats(startSecs);

                    _authoring.Add(newEvent);

                    //now find a nearby  note-off pair

                    /*foreach (var pairedEvent in events)
                     * {
                     * if (_IsNearEvent(pairedEvent, midiEvent) && (pairedEvent.Event is NoteOffEvent) && (curNote >= 0) && (curNote == (pairedEvent.Event as NoteOffEvent).NoteNumber)) //found paired note off
                     * {
                     *    float endSecs = pairedEvent.TimeAs<MetricTimeSpan>(_tempoMap).TotalMicroseconds / 1000000.0f;
                     *    newEvent.NoteOffBeat = SecsToBeats(endSecs);
                     *
                     *    if (newEvent.IsValid()) //done?
                     *    {
                     *       _authoring.Add(newEvent);
                     *
                     *       //Debug.Log("added event " + newEvent.NoteOnBeat + " -> " + newEvent.NoteOffBeat);
                     *    }
                     *
                     *    break;
                     * }
                     * }*/
                }
            }
        }

        Debug.Log("Found " + _authoring.Count + " authoring events!");
    }