Example #1
0
        private static EventParser GetEventParser(Func <object[], MidiEvent> eventCreator, params ParameterParser[] parametersParsers)
        {
            return((p, s) =>
            {
                if (p.Length < parametersParsers.Length)
                {
                    CsvError.ThrowBadFormat("Invalid number of parameters provided.");
                }

                var parameters = new List <object>(parametersParsers.Length);

                for (int i = 0; i < parametersParsers.Length; i++)
                {
                    var parameterParser = parametersParsers[i];

                    try
                    {
                        var parameter = parameterParser(p[i], s);
                        parameters.Add(parameter);
                    }
                    catch
                    {
                        CsvError.ThrowBadFormat($"Parameter ({i}) is invalid.");
                    }
                }

                return eventCreator(parameters.ToArray());
            });
        }
        private static HeaderChunk ParseHeader(Record record, MidiFileCsvConversionSettings settings)
        {
            var parameters = record.Parameters;

            var format       = default(MidiFileFormat?);
            var timeDivision = default(short);

            switch (settings.CsvLayout)
            {
            case MidiFileCsvLayout.DryWetMidi:
                {
                    if (parameters.Length < 2)
                    {
                        CsvError.ThrowBadFormat(record.LineNumber, "Parameters count is invalid.");
                    }

                    MidiFileFormat formatValue;
                    if (Enum.TryParse(parameters[0], true, out formatValue))
                    {
                        format = formatValue;
                    }

                    if (!short.TryParse(parameters[1], out timeDivision))
                    {
                        CsvError.ThrowBadFormat(record.LineNumber, "Invalid time division.");
                    }
                }
                break;

            case MidiFileCsvLayout.MidiCsv:
            {
                if (parameters.Length < 3)
                {
                    CsvError.ThrowBadFormat(record.LineNumber, "Parameters count is invalid.");
                }

                ushort formatValue;
                if (ushort.TryParse(parameters[0], out formatValue) && Enum.IsDefined(typeof(MidiFileFormat), formatValue))
                {
                    format = (MidiFileFormat)formatValue;
                }

                if (!short.TryParse(parameters[2], out timeDivision))
                {
                    CsvError.ThrowBadFormat(record.LineNumber, "Invalid time division.");
                }
            }
            break;
            }

            return(new HeaderChunk
            {
                FileFormat = format != null ? (ushort)format.Value : ushort.MaxValue,
                TimeDivision = TimeDivisionFactory.GetTimeDivision(timeDivision)
            });
        }
        private static TimedMidiEvent[] ParseNote(Record record, MidiFileCsvConversionSettings settings)
        {
            if (record.TrackNumber == null)
            {
                CsvError.ThrowBadFormat(record.LineNumber, "Invalid track number.");
            }

            if (record.Time == null)
            {
                CsvError.ThrowBadFormat(record.LineNumber, "Invalid time.");
            }

            var parameters = record.Parameters;

            if (parameters.Length < 5)
            {
                CsvError.ThrowBadFormat(record.LineNumber, "Invalid number of parameters provided.");
            }

            var i = -1;

            try
            {
                var channel    = (FourBitNumber)TypeParser.FourBitNumber(parameters[++i], settings);
                var noteNumber = (SevenBitNumber)TypeParser.NoteNumber(parameters[++i], settings);

                ITimeSpan length = null;
                TimeSpanUtilities.TryParse(parameters[++i], settings.NoteLengthType, out length);

                var velocity    = (SevenBitNumber)TypeParser.SevenBitNumber(parameters[++i], settings);
                var offVelocity = (SevenBitNumber)TypeParser.SevenBitNumber(parameters[++i], settings);

                return(new[]
                {
                    new TimedMidiEvent(record.Time, new NoteOnEvent(noteNumber, velocity)
                    {
                        Channel = channel
                    }),
                    new TimedMidiEvent(record.Time.Add(length, TimeSpanMode.TimeLength), new NoteOffEvent(noteNumber, offVelocity)
                    {
                        Channel = channel
                    }),
                });
            }
            catch
            {
                CsvError.ThrowBadFormat(record.LineNumber, $"Parameter ({i}) is invalid.");
            }

            return(null);
        }
        private static Record ReadRecord(CsvReader csvReader, int lineNumber, MidiFileCsvConversionSettings settings)
        {
            var record = csvReader.ReadRecord();

            if (record == null)
            {
                return(null);
            }

            var values = record.Values;

            if (values.Length < 3)
            {
                CsvError.ThrowBadFormat(record.LineNumber, "Missing required parameters.");
            }

            int parsedTrackNumber;
            var trackNumber = int.TryParse(values[0], out parsedTrackNumber)
                ? (int?)parsedTrackNumber
                : null;

            ITimeSpan time = null;

            TimeSpanUtilities.TryParse(values[1], settings.TimeType, out time);

            var recordType = values[2];

            if (string.IsNullOrEmpty(recordType))
            {
                CsvError.ThrowBadFormat(record.LineNumber, "Record type isn't specified.");
            }

            var parameters = values.Skip(3).ToArray();

            return(new Record(record.LineNumber, trackNumber, time, recordType, parameters));
        }
        private static MidiEvent ParseEvent(Record record, MidiFileCsvConversionSettings settings)
        {
            if (record.TrackNumber == null)
            {
                CsvError.ThrowBadFormat(record.LineNumber, "Invalid track number.");
            }

            if (record.Time == null)
            {
                CsvError.ThrowBadFormat(record.LineNumber, "Invalid time.");
            }

            var eventParser = EventParserProvider.Get(record.RecordType, settings.CsvLayout);

            try
            {
                return(eventParser(record.Parameters, settings));
            }
            catch (FormatException ex)
            {
                CsvError.ThrowBadFormat(record.LineNumber, "Invalid format of event record.", ex);
                return(null);
            }
        }
Example #6
0
        private static EventParser GetBytesBasedEventParser(Func <object[], MidiEvent> eventCreator, params ParameterParser[] parametersParsers)
        {
            return((p, s) =>
            {
                if (p.Length < parametersParsers.Length)
                {
                    CsvError.ThrowBadFormat("Invalid number of parameters provided.");
                }

                var parameters = new List <object>(parametersParsers.Length);
                var i = 0;

                for (i = 0; i < parametersParsers.Length; i++)
                {
                    var parameterParser = parametersParsers[i];

                    try
                    {
                        var parameter = parameterParser(p[i], s);
                        parameters.Add(parameter);
                    }
                    catch
                    {
                        CsvError.ThrowBadFormat($"Parameter ({i}) is invalid.");
                    }
                }

                if (p.Length < i)
                {
                    CsvError.ThrowBadFormat("Invalid number of parameters provided.");
                }

                int bytesNumber = 0;

                try
                {
                    bytesNumber = int.Parse(p[i]);
                    parameters.Add(bytesNumber);
                }
                catch
                {
                    CsvError.ThrowBadFormat($"Parameter ({i}) is invalid.");
                }

                i++;
                if (p.Length < i + bytesNumber)
                {
                    CsvError.ThrowBadFormat("Invalid number of parameters provided.");
                }

                try
                {
                    var bytes = p.Skip(i)
                                .Select(x =>
                    {
                        var b = (byte)TypeParser.Byte(x, s);
                        i++;
                        return b;
                    })
                                .ToArray();
                    parameters.Add(bytes);
                }
                catch
                {
                    CsvError.ThrowBadFormat($"Parameter ({i}) is invalid.");
                }

                return eventCreator(parameters.ToArray());
            });
        }
        public static MidiFile ConvertToMidiFile(Stream stream, MidiFileCsvConversionSettings settings)
        {
            var midiFile = new MidiFile();
            var events   = new Dictionary <int, List <TimedMidiEvent> >();

            using (var csvReader = new CsvReader(stream, settings.CsvDelimiter))
            {
                var    lineNumber = 0;
                Record record;

                while ((record = ReadRecord(csvReader, lineNumber, settings)) != null)
                {
                    var recordType = GetRecordType(record.RecordType, settings);
                    if (recordType == null)
                    {
                        CsvError.ThrowBadFormat(lineNumber, "Unknown record.");
                    }

                    switch (recordType)
                    {
                    case RecordType.Header:
                    {
                        var headerChunk = ParseHeader(record, settings);
                        midiFile.TimeDivision   = headerChunk.TimeDivision;
                        midiFile.OriginalFormat = (MidiFileFormat)headerChunk.FileFormat;
                    }
                    break;

                    case RecordType.TrackChunkStart:
                    case RecordType.TrackChunkEnd:
                    case RecordType.FileEnd:
                        break;

                    case RecordType.Event:
                    {
                        var midiEvent        = ParseEvent(record, settings);
                        var trackChunkNumber = record.TrackNumber.Value;

                        AddTimedEvents(events, trackChunkNumber, new TimedMidiEvent(record.Time, midiEvent));
                    }
                    break;

                    case RecordType.Note:
                    {
                        var noteEvents       = ParseNote(record, settings);
                        var trackChunkNumber = record.TrackNumber.Value;

                        AddTimedEvents(events, trackChunkNumber, noteEvents);
                    }
                    break;
                    }

                    lineNumber = record.LineNumber + 1;
                }
            }

            if (!events.Keys.Any())
            {
                return(midiFile);
            }

            var tempoMap = GetTempoMap(events.Values.SelectMany(e => e), midiFile.TimeDivision);

            var trackChunks = new TrackChunk[events.Keys.Max() + 1];

            for (int i = 0; i < trackChunks.Length; i++)
            {
                List <TimedMidiEvent> timedMidiEvents;
                trackChunks[i] = events.TryGetValue(i, out timedMidiEvents)
                    ? timedMidiEvents.Select(e => new TimedEvent(e.Event, TimeConverter.ConvertFrom(e.Time, tempoMap))).ToTrackChunk()
                    : new TrackChunk();
            }

            midiFile.Chunks.AddRange(trackChunks);

            return(midiFile);
        }
Example #8
0
        public static IEnumerable <Note> ConvertToNotes(Stream stream, TempoMap tempoMap, NoteCsvConversionSettings settings)
        {
            using (var csvReader = new CsvReader(stream, settings.CsvDelimiter))
            {
                CsvRecord record = null;

                while ((record = csvReader.ReadRecord()) != null)
                {
                    var values = record.Values;
                    if (values.Length < 6)
                    {
                        CsvError.ThrowBadFormat(record.LineNumber, "Missing required parameters.");
                    }

                    ITimeSpan time;
                    if (!TimeSpanUtilities.TryParse(values[0], settings.TimeType, out time))
                    {
                        CsvError.ThrowBadFormat(record.LineNumber, "Invalid time.");
                    }

                    FourBitNumber channel;
                    if (!FourBitNumber.TryParse(values[1], out channel))
                    {
                        CsvError.ThrowBadFormat(record.LineNumber, "Invalid channel.");
                    }

                    SevenBitNumber noteNumber;
                    if (!TryParseNoteNumber(values[2], settings.NoteNumberFormat, out noteNumber))
                    {
                        CsvError.ThrowBadFormat(record.LineNumber, "Invalid note number or letter.");
                    }

                    ITimeSpan length;
                    if (!TimeSpanUtilities.TryParse(values[3], settings.NoteLengthType, out length))
                    {
                        CsvError.ThrowBadFormat(record.LineNumber, "Invalid length.");
                    }

                    SevenBitNumber velocity;
                    if (!SevenBitNumber.TryParse(values[4], out velocity))
                    {
                        CsvError.ThrowBadFormat(record.LineNumber, "Invalid velocity.");
                    }

                    SevenBitNumber offVelocity;
                    if (!SevenBitNumber.TryParse(values[5], out offVelocity))
                    {
                        CsvError.ThrowBadFormat(record.LineNumber, "Invalid off velocity.");
                    }

                    var convertedTime   = TimeConverter.ConvertFrom(time, tempoMap);
                    var convertedLength = LengthConverter.ConvertFrom(length, convertedTime, tempoMap);

                    yield return(new Note(noteNumber, convertedLength, convertedTime)
                    {
                        Channel = channel,
                        Velocity = velocity,
                        OffVelocity = offVelocity
                    });
                }
            }
        }