Track[] Parse(IVsqx vsq) { var resolution = vsq.MasterTrack.Resolution; var measureTicks = resolution * 4; // for 4/4 var preMeasureTicks = Enumerable.Range(0, vsq.MasterTrack.PreMeasure) .Select((i) => vsq.MasterTrack.TimeSig.First((sig) => sig.Measure <= i)) .Select((sig) => measureTicks / sig.Denominator * sig.Nume) .Sum(); var firstTempo = vsq.MasterTrack.Tempo.First().PushTo(vsq.MasterTrack.Tempo.TakeWhile((t) => t.Tick <= preMeasureTicks)).Last(); firstTempo.Tick = preMeasureTicks; var tempo = vsq.MasterTrack.Tempo.SkipWhile((t) => t.Tick < preMeasureTicks) .SelectReferencePrev <IVSTempo, Tempo>((v, p) => new Tempo(v.Tick - preMeasureTicks, p.Select((pt) => pt.TotalTime + (v.Tick - preMeasureTicks - pt.Tick) / pt.TickPerTime).FirstOrDefault(), v.BPM * 0.01, resolution) ) .ToRangeDictionary((v) => v.Tick, IntervalMode.OpenInterval); return(vsq.VSTrack.Select((t) => { var parts = Optional <IVSPart[]> .FromNull(t.Part) .SelectMany(_ => _) .Select((p) => { var partTick = p.Tick - preMeasureTicks; var partStartTime = tempo[partTick].TickToTime(partTick); var pbs = GetControlChange(p, "S", 2.0, partTick, tempo); var pitchBend = GetControlChange(p, "P", 0.0, partTick, tempo) .ToRangeDictionary((e) => e.Key, e => e.Value / 8192.0 * pbs[e.Key], IntervalMode.OpenInterval); var portamento = GetControlChange(p, "T", 64.0, partTick, tempo); var notes = p.Note .Select((n) => { var tick = partTick + n.Tick; var time = tempo[tick].TickToTime(tick); var length = tempo[tick + n.Duration].TickToTime(tick + n.Duration) - time; var pot = new Portamento((int)portamento[tempo[tick + n.Duration].TickToTime(tick + n.Duration)]); return new Note(n.Character, time - partStartTime, length, n.NoteNumber, GetVibratoInfo(n, partTick, length, tempo), pot); }) .ToRangeDictionary((n) => n.Position, IntervalMode.OpenInterval); return new Part(partStartTime, tempo[partTick + p.PlayTime].TickToTime(partTick + p.PlayTime) - partStartTime, notes, pitchBend); }) .ToRangeDictionary((p) => p.TrackPosition, IntervalMode.OpenInterval); return new Track(t.Name, parts); }).ToArray()); }
Track[] Parse(Vpr vpr) { const int resolution = 480; IEnumerable <VprValue> vprTempo = vpr.MasterTrack.Tempo.Events; if ((vprTempo.OrderBy(t => t.Pos).FirstOrDefault()?.Pos ?? int.MaxValue) != 0) { vprTempo = new VprValue { Pos = 0, Value = vpr.MasterTrack.Tempo.Global.Value }.PushTo(vprTempo); } var tempo = vprTempo .SelectReferencePrev <VprValue, Tempo>((v, p) => new Tempo(v.Pos, p.Select((pt) => pt.TotalTime + v.Pos / pt.TickPerTime).FirstOrDefault(), v.Value * 0.01, resolution)) .ToRangeDictionary(v => v.Tick, IntervalMode.OpenInterval); return(vpr.Tracks.Where(t => t.Type == 0) .Select(t => { var parts = Optional <VprPart[]> .FromNull(t.Parts) .SelectMany(_ => _) .Select(p => { var partTick = p.Pos; var partStartTime = tempo[partTick].TickToTime(partTick); var pbs = GetControlChange(p, "pitchBendSens", 2.0, partTick, tempo); var pitchBend = GetControlChange(p, "pitchBend", 0.0, partTick, tempo) .ToRangeDictionary(e => e.Key, e => e.Value / 8192.0 * pbs[e.Key], IntervalMode.OpenInterval); var portamento = GetControlChange(p, "portamento", 64.0, partTick, tempo); var notes = p.Notes .Select(n => { var tick = partTick + n.Pos; var time = tempo[tick].TickToTime(tick); var length = tempo[tick + n.Duration].TickToTime(tick + n.Duration) - time; var pot = new Portamento((int)portamento[tempo[tick + n.Duration].TickToTime(tick + n.Duration)]); return new Note(n.Lyric, time - partStartTime, length, n.NoteNumber, GetVibratoInfo(n, partTick, tempo), pot); }) .ToRangeDictionary((n) => n.Position, IntervalMode.OpenInterval); return new Part(partStartTime, tempo[partTick + p.Duration].TickToTime(partTick + p.Duration) - partStartTime, notes, pitchBend); }) .ToRangeDictionary((p) => p.TrackPosition, IntervalMode.OpenInterval); return new Track(t.Name, parts); }).ToArray()); }