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); } }
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); }
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 }); } } }