public int AddBend(double deltaMs, double deltaCents, bool endless = false)
        {
            double deltaSamples = _format.sampleRate * deltaMs / 1000;
            var    bend         = new Bend {
                centsPerSample = deltaCents / deltaSamples,
                refCount       = endless ? 1 : 0
            };

            _bends.Add(bend);
            return(_bends.Count - 1);
        }
        public bool Fill(byte[] buffer)
        {
            if (_parts.Count == 0)
            {
                return(false);         // stop if no partials left on timeline
            }
            int bufferPos         = 0; // in bytes
            int bufferSampleCount = buffer.Length / _format.bytesPerSample;

            var endedParts = new List <int>();

            for (int i = 0; i < bufferSampleCount / _format.channels; ++i)
            {
                int[] sampleValues = new int[_format.channels]; // zeroes

                // step bends
                if (_bends.Count > 0)
                {
                    for (int j = 0; j < _bends.Count; ++j)
                    {
                        _bends[j].MakeStep();
                    }
                }

                // step parts
                if (_parts.Count > 0)
                {
                    for (int j = 0; j < _parts.Count; ++j)
                    {
                        Part p = _parts[j]; // copy if Part is struct

                        if (p.endSample <= _currentSample)
                        {
                            if (p.endSample != _currentSample)
                            {
                                Debug.WriteLine("Warning! Part skipped: {0}", p); // partial added too late ?
                            }
                            endedParts.Add(j);
                            continue;
                        }

                        if (p.startSample <= _currentSample)
                        {
                            // starting
                            if (p.startSample == _currentSample)
                            {
                                if (p.bend != null)
                                {
                                    p.bendStartFactor = p.bend.currentFactor;
                                }
                            }
                            // playing
                            if (p.bend != null)
                            {
                                // change current phase step for this copy //!!! valid for struct Part only
                                double factor = p.bend.currentFactor / p.bendStartFactor;
                                p.partial.phaseStep = (int)(p.partial.phaseStep * factor);
                            }
                            if (_format.channels == 2)   // stereo
                            {
                                int v0, v1;
                                p.partial.GetNextStereoValue(p.balance16, out v0, out v1);
                                sampleValues[0] += v0;
                                sampleValues[1] += v1;
                            }
                            else     // ignore balance
                            {
                                int v = p.partial.GetNextValue();
                                for (int c = 0; c < sampleValues.Length; ++c)
                                {
                                    sampleValues[c] += v;
                                }
                            }

                            p.partial.phaseStep = _parts[j].partial.phaseStep; // !!! put the original step back
                            _parts[j]           = p;                           // for struct
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (endedParts.Count > 0)
                    {
                        for (int k = endedParts.Count - 1; k >= 0; --k)
                        {
                            int j = endedParts[k];

                            if (_parts[j].bend != null)
                            {
                                Bend bend = _parts[j].bend;
                                bend.refCount -= 1;
                                if (bend.refCount == 0)
                                {
                                    _bends.Remove(bend);
                                }
                            }

                            _parts.RemoveAt(j);
                        }
                        endedParts.Clear();
                    }
                }

                _currentSample += 1;

                // Write sample value to all channels
                for (int c = 0; c < _format.channels; ++c)
                {
                    _format.WriteInt(buffer, bufferPos, sampleValues[c]);
                    bufferPos += _format.bytesPerSample;
                }
            }

            //Debug.WriteLine(FormatBuffer(buffer));

            return(true);
        }