/// <summary>
        /// Draw waveform. Argument's units are grid divisions (GD)
        /// </summary>
        /// <param name="channel">Channel</param>
        /// <param name="smpBeg">Index of first sample</param>
        /// <param name="smpEnd">Index of last sample</param>
        /// <param name="pxStart">Start pixel</param>
        /// <param name="pxPerSample">Pixels per sample</param>
        /// <param name="color">Waveform color</param>
        public void PlotFloatLogic(
            OscChannel channel,
            int smpBeg,
            int smpEnd,
            float pxStart,
            float pxPerSample,
            Color color)
        {
            // do not render empty buffer
            const int CHAR_OFFSET_Y = -10;
            const int CHAR_OFFSET_X = -66;
            var       position      = channel.Position;
            var       texCenterY    = oscSettings.textureCenter.y;
            var       pixPerDivs    = oscSettings.pixelsPerDivision;
            var       topY          = Mathf.RoundToInt((position + channel.Scale) * pixPerDivs + texCenterY);
            var       botY          = Mathf.RoundToInt(position * pixPerDivs + texCenterY);
            // first sample position
            var fpx = pxStart;
            var x1  = Mathf.RoundToInt(pxStart - pxPerSample);
            var v1  = (int)(channel.GetFloat(smpBeg - 1) - position);

            // iterate over all samples (starts from sample 2)
            for (var i = smpBeg; i <= smpEnd; i++)
            {
                var x2 = Mathf.RoundToInt(fpx);
                var v2 = (int)(channel.GetFloat(i) - position);
                if (v1 == v2)
                {
                    if (i != smpEnd)
                    {
                        v1   = v2;
                        fpx += pxPerSample;
                        continue;                         // skip
                    }
                    else
                    {
                        // horizontal lines
                        OscUtils.PlotLine(screenTexture, x1, topY, x2 - 1, topY, color);
                        OscUtils.PlotLine(screenTexture, x1, botY, x2 - 1, botY, color);
                        return;
                    }
                }
                // horizontal lines
                OscUtils.PlotLine(screenTexture, x1, topY, x2 - 2, topY, color);
                OscUtils.PlotLine(screenTexture, x1, botY, x2 - 2, botY, color);
                // cross over lines
                OscUtils.PlotLine(screenTexture, x2 - 2, topY, x2, botY, color);
                OscUtils.PlotLine(screenTexture, x2 - 2, botY, x2, topY, color);
                // display value (previous value)
                OscFont.DrawText(screenTexture, v1.ToString("x8"), x2 + CHAR_OFFSET_X, botY + CHAR_OFFSET_Y, color);
                x1   = x2;
                v1   = v2;
                fpx += pxPerSample;
            }
        }
        /// <summary>
        /// Draw marker at the x,y position in the division units
        /// </summary>
        /// <param name="text"></param>
        /// <param name="color"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="scale">Vertical scale</param>
        /// <param name="position">Vertical position</param>
        /// <param name="clampPosition">If label does not fit on screen render it with blinking</param>
        public void DrawLabel(string text, float x, float y, Color color, bool clampPosition = false)
        {
            var pxX      = oscSettings.GetPixelPositionIntX(x);
            var pxY      = oscSettings.GetPixelPositionIntY(y);
            var isNotFit = !oscSettings.TestPixelInsideScreenY(pxY);

            if (isNotFit)
            {
                // if the label outside it modify name
                if (clampPosition)
                {
                    pxY   = oscSettings.ClampPixelInsideScreenY(pxY);
                    text += '!';                     // mark it clamped
                }
                else
                {
                    return;                     // do not render label outside
                }
            }
            // Render little cross hor. and vert. lines.
            OscUtils.PlotLine(screenTexture, pxX, pxY, pxX + 16, pxY, color);
            OscUtils.PlotLine(screenTexture, pxX, pxY - 8, pxX, pxY + 8, color);
            // Render text (if text is not fit move it below the line)
            const int CHAR_HEIGHT = 8;
            const int CHAR_OFFSET = 2;

            if (pxY < oscSettings.textureSize.y - (CHAR_HEIGHT + CHAR_OFFSET))
            {
                // fit on screen
                OscFont.DrawText(screenTexture, text, pxX + 1, pxY + CHAR_OFFSET, color);
            }
            else
            {
                // does not fit on screen
                OscFont.DrawText(screenTexture, text, pxX + 1, pxY - (CHAR_HEIGHT + CHAR_OFFSET), color);
            }
        }