public static IEnumerable<Track> ParseMidi(string fileName) { var tracks = new List<Track>(); var file = new MidiFile(fileName); var tempo = 120; for(var trackNumber = 0; trackNumber < file.Tracks; ++trackNumber) { var events = file.Events[trackNumber]; var tempoEvent = events.FirstOrDefault(c => c is TempoEvent) as TempoEvent; if(tempoEvent != null) { tempo = (int)tempoEvent.Tempo; } } var channel = 0; for(var trackNumber = 0; trackNumber < file.Tracks; ++trackNumber, ++channel) { var phrases = new List<Phrase>(); var events = file.Events[trackNumber]; var path = events.FirstOrDefault(c => c is PatchChangeEvent) as PatchChangeEvent; if(path != null && PatchChangeEvent.GetPatchName(path.Patch) == "Steel Drums") { continue; } var mediaPatch = PatchChangeEvent.GetPatchName(path?.Patch ?? 0) .IndexOf("bass", StringComparison.InvariantCultureIgnoreCase) != -1 ? MediaPatch.Bass : MediaPatch.CleanGuitar; var notes = events.OfType<NoteOnEvent>().GroupBy(c => c.AbsoluteTime); long lastTime = 0; foreach(var noteCollection in notes) { if(noteCollection.Key - lastTime > 0) { var pauseTime = noteCollection.Key - lastTime; phrases.Add(new Phrase(pauseTime / WholeNoteDuration)); } var duration = noteCollection.Max(c => c.NoteLength); var phrase = new Phrase { Duration = duration / WholeNoteDuration, Notes = noteCollection.Select(c => Note.FromId(c.NoteNumber)).ToArray() }; lastTime = noteCollection.Key + duration; phrases.Add(phrase); } tracks.Add(new Track { Tempo = tempo, Patch = mediaPatch, Phrases = phrases.ToArray(), Channel = channel }); } return tracks; }
private ISampleProvider CreateSampleProvider(Phrase phrase, int offset, bool letRingPhrase) { if(phrase.Notes?.Any() ?? false) { var phraseDuration = phrase.GetPhraseSeconds(Tempo); var additionalDuration = LetRingEnabled || letRingPhrase ? CurrentLetRingFadeOut : 0; var sampleProviders = phrase.Notes.Select(n => MediaBank.GetMedia(n)?.ToSampleProvider()) .Where(s => s != null).ToArray(); if(sampleProviders.Any()) { var phraseSampleProvider = new FadeOutSampleProvider(sampleProviders.Length > 1 ? new DelayedMixingSampleProvider(sampleProviders, DefaultChordNotesDelay, false) : sampleProviders.Single(), phraseDuration + additionalDuration, DefaultFadeOutTime); if(offset > 0) { return new OffsetSampleProvider(phraseSampleProvider) { DelayBySamples = offset }; } return phraseSampleProvider; } } return null; }
public static Track ParseString(string songStr) { var phrases = new List<Phrase>(); if(!string.IsNullOrWhiteSpace(songStr)) { var noteModifier = PlayingCommand.None; foreach(var token in songStr.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries)) { if(token.StartsWith("=")) //command { var command = new Phrase(PlayingCommand.None); switch(token) { case "=LROn=": command.Command = PlayingCommand.LetItRingOn; break; case "=LROff=": command.Command = PlayingCommand.LetItRingOff; break; case "=LRw=": command.Command = PlayingCommand.LetRingWhole; break; case "=LRh=": command.Command = PlayingCommand.LetRingHalf; break; case "=LRq=": command.Command = PlayingCommand.LetRingQuarter; break; case "=LR=": noteModifier = PlayingCommand.LetRingNotes; continue; default: throw new Exception($"Unknown command: {token}"); } phrases.Add(command); } else { try { var dots = token.Count(c => c == '.'); var duration = token[token.Length - 1 - dots]; var phraseDuration = Durations.ContainsKey(duration) ? Durations[duration] : Durations['w']; if(dots > 0) { var tempDuration = phraseDuration; for(var i = 0; i < dots; i++) { tempDuration /= 2; phraseDuration += tempDuration; } } var notesString = token.Substring(0, token.Length - 1 - dots); var notes = notesString.Split(new[] {'_'}, StringSplitOptions.RemoveEmptyEntries) .Select(Note.FromString); var phrase = new Phrase(phraseDuration, notes.Distinct().ToArray()) {Command = noteModifier}; noteModifier = PlayingCommand.None; phrases.Add(phrase); } catch(Exception) { throw new Exception($"Unable to parse phrase: {token}"); } } } } return new Track { Patch = MediaPatch.CleanGuitar, Phrases = phrases, Tempo = 60, Channel = 0 }; }