public string Encode(IEnumerable <BmsEvent> events, Func <BigRational?, string> encodeValue,
                             BigRational measureLength, int quantize)
        {
            var eventList = events.AsList();

            // round up and multiply for longer measures (100% minimoo-G would be a nightmare otherwise)
            var maxQ = Math.Max(quantize, (int)((measureLength + BigRational.OneHalf).GetWholePart() * quantize));
            var q    = _quantizer.GetQuantization(eventList.Select(e => e.Offset), BigInteger.One, maxQ);

            var buffer = Enumerable.Range(0, q).Select(i => (BigRational?)null).ToArray();

            foreach (var ev in eventList)
            {
                var i = (int)(ev.Offset * q);
                buffer[i] = ev.Value;
            }

            var builder = new StringBuilder();

            foreach (var i in buffer)
            {
                builder.Append(encodeValue(i));
            }

            return(builder.ToString());
        }
        private IEnumerable <char[][]> EncodeMeasures(IEnumerable <Note> notes)
        {
            var notesList = notes.AsList();

            if (!notesList.Any())
            {
                yield break;
            }

            var columns    = notesList.Max(n => n.Column) + 1;
            var measures   = notesList.GroupBy(n => n.MetricOffset.GetWholePart()).AsList();
            var maxMeasure = measures.Max(m => m.Key);

            for (var measureNumber = 0; measureNumber <= maxMeasure; measureNumber++)
            {
                var measure      = measures.FirstOrDefault(m => m.Key == measureNumber) ?? Enumerable.Empty <Note>();
                var measureNotes = measure.ToArray();
                var quantization = _quantizer.GetQuantization(measureNotes.Select(n => n.MetricOffset),
                                                              MinimumQuantization, MaximumQuantization);
                var half = new BigRational(1, quantization * 2);

                var grid = Enumerable.Range(0, quantization)
                           .Select(i => Enumerable.Repeat(NoteType.None, columns).ToArray()).ToArray();

                foreach (var note in measureNotes)
                {
                    var row = (int)(note.MetricOffset.GetFractionPart() * quantization + half);
                    if (row < 0)
                    {
                        row = 0;
                    }
                    if (row >= quantization)
                    {
                        row = quantization - 1;
                    }
                    grid[row][note.Column] = note.Type;
                }

                yield return(grid);
            }
        }