Example #1
0
    public void Draw(Rect displayRect, WaveDisplayState displayState)
    {
        if (displayState.displayType != WaveDisplayType.Line &&
            displayState.samplesPerPixel != cachedSamplesPerPixel)
        {
            // New list instead?  Clear takes O(n) time, whereas creating a new list may be faster.
            //  Would probably thrash memory more, though.
            System.Array.Clear(cachedData, 0, cachedData.Length);
            cachedSamplesPerPixel = displayState.samplesPerPixel;
        }

        switch (displayState.displayType)
        {
        case WaveDisplayType.Line:
            DrawWaves(displayRect, displayState);
            break;
        case WaveDisplayType.MinMax:
            DrawMinMax(displayRect, displayState);
            break;
        case WaveDisplayType.RMS:
            DrawRMS(displayRect, displayState);
            break;
        case WaveDisplayType.Both:
            DrawMinMax(displayRect, displayState);
            DrawRMS(displayRect, displayState);
            break;
        }
    }
Example #2
0
    void DrawMinMax(Rect waveArea, WaveDisplayState displayState)
    {
        UnityEditor.Handles.color = new Color(1f, 104f / 255f, 0f, KoreographerColors.HandleFullAlpha);

        int amplitude = (int)(channelAmplitudePercent * (waveArea.height / 2f));

        Vector2 startPoint = Vector2.zero;
        Vector2 endPoint = Vector2.zero;

        float minSample, maxSample, curSample;
        int sampleIdxForPixel;

        int cacheIdxOffset = displayState.firstSamplePackToDraw / displayState.samplesPerPixel;

        for (int i = 0; i < waveArea.width && displayState.firstSamplePackToDraw + (i * displayState.samplesPerPixel) < sampleData.Length; ++i)
        {
            WaveformCacheEntry entry;

            if (cachedData[cacheIdxOffset + i] == null)
            {
                entry = new WaveformCacheEntry();
                cachedData[cacheIdxOffset + i] = entry;
            }
            else
            {
                entry = cachedData[cacheIdxOffset + i];
            }

            if (!entry.minMaxValid)
            {
                minSample = 1f;
                maxSample = -1f;

                sampleIdxForPixel = i * displayState.samplesPerPixel;

                for (int j = 0; j < displayState.samplesPerPixel && displayState.firstSamplePackToDraw + sampleIdxForPixel + j < sampleData.Length; j++)
                {
                    curSample = sampleData[displayState.firstSamplePackToDraw + sampleIdxForPixel + j];
                    minSample = Mathf.Min(minSample, curSample);
                    maxSample = Mathf.Max(maxSample, curSample);
                }

                // Subtract because positive is down!
                entry.minMaxValues.x = waveArea.center.y - (maxSample * amplitude);
                entry.minMaxValues.y = waveArea.center.y - (minSample * amplitude);

                // Update the cache entry!
                entry.minMaxValid = true;
            }

            // Draw a vertical line.
            startPoint.x = waveArea.x + i;
            endPoint.x = startPoint.x;

            startPoint.y = entry.minMaxValues.x;
            endPoint.y = entry.minMaxValues.y;

            UnityEditor.Handles.DrawLine(startPoint, endPoint);
        }
    }
Example #3
0
    void DrawRMS(Rect waveArea, WaveDisplayState displayState)
    {
        UnityEditor.Handles.color = new Color(1f, 0.58431f, 0f, KoreographerColors.HandleFullAlpha);

        int amplitude = (int)(channelAmplitudePercent * (waveArea.height / 2f));

        Vector2 startPoint = Vector2.zero;
        Vector2 endPoint = Vector2.zero;

        float curSample, peak;
        int sampleIdxForPixel;

        int cacheIdxOffset = displayState.firstSamplePackToDraw / displayState.samplesPerPixel;

        // Calculate the waveform via RMS!
        for (int i = 0; i < waveArea.width && displayState.firstSamplePackToDraw + (i * displayState.samplesPerPixel) < sampleData.Length; ++i)
        {
            WaveformCacheEntry entry;

            if (cachedData[cacheIdxOffset + i] == null)
            {
                entry = new WaveformCacheEntry();
                cachedData[cacheIdxOffset + i] = entry;
            }
            else
            {
                entry = cachedData[cacheIdxOffset + i];
            }

            if (!entry.rmsValid)
            {
                peak = 0;

                sampleIdxForPixel = i * displayState.samplesPerPixel;

                for (int j = 0; j < displayState.samplesPerPixel && displayState.firstSamplePackToDraw + sampleIdxForPixel + j < sampleData.Length; j++)
                {
                    curSample = sampleData[displayState.firstSamplePackToDraw + sampleIdxForPixel + j];

                    peak += (curSample * curSample);
                }

                peak = Mathf.Sqrt(peak / (float)displayState.samplesPerPixel);

                entry.rmsValues.x = waveArea.center.y - (peak * amplitude);
                entry.rmsValues.y = waveArea.center.y + (peak * amplitude);

                // Update the cache entry!
                entry.rmsValid = true;
            }

            // Draw vertical lines.
            startPoint.x = waveArea.x + i;
            endPoint.x = startPoint.x;

            startPoint.y = entry.rmsValues.x;
            endPoint.y = entry.rmsValues.y;

            UnityEditor.Handles.DrawLine(startPoint, endPoint);
        }
    }
Example #4
0
    void DrawWaves(Rect waveArea, WaveDisplayState displayState)
    {
        UnityEditor.Handles.color = new Color(1f, 149f / 255f, 0f, KoreographerColors.HandleFullAlpha);

        int startSample = displayState.firstSamplePackToDraw;
        int amplitude = (int)(channelAmplitudePercent * (waveArea.height / 2f));

        Vector2 startPoint = Vector2.zero;
        Vector2 endPoint = Vector2.zero;

        float lastY = waveArea.center.y + (sampleData[startSample] * amplitude);

        for (int i = 1; i < waveArea.width && i + startSample < sampleData.Length; ++i)
        {
            endPoint.x = waveArea.x + i;
            startPoint.x = endPoint.x - 1;	// Back us up by one!

            // Get y's for left channel.
            startPoint.y = lastY;
            endPoint.y = waveArea.center.y + (sampleData[startSample + i] * amplitude);
            UnityEditor.Handles.DrawLine(startPoint, endPoint);

            // Store previous y for next time!
            lastY = endPoint.y;
        }
    }
Example #5
0
 float GetDrawStart(WaveDisplayState displayState)
 {
     // TODO: Embed this info into the skin!  This was reconstructed from Draw().
     return GUI.skin.box.padding.left + GUI.skin.box.margin.left + displayState.drawStartOffsetInPixels;
 }
Example #6
0
    public void Draw(Rect displayRect, WaveDisplayState displayState, Koreography koreo, bool bShowPlayhead, List<KoreographyEvent> selectedEvents)
    {
        // Draw background.
        Color originalBG = GUI.backgroundColor;
        GUI.backgroundColor = mainBGColor;

        GUI.Box(displayRect, "");

        GUI.backgroundColor = originalBG;

        GUI.BeginGroup(displayRect);

        // Calculate drawing metrics for channels.
        float left = GUI.skin.box.padding.left + 1f;
        float top = GUI.skin.box.padding.top;
        float width = GetChannelPixelWidthForWindow((int)displayRect.width);
        float height = (displayRect.height - GUI.skin.box.padding.vertical) / MAX_CHANNELS_TO_DRAW;

        Rect contentRect = new Rect(left + displayState.drawStartOffsetInPixels, top, width - displayState.drawStartOffsetInPixels, displayRect.height - GUI.skin.box.padding.vertical);
        // Adjust for start offset!
        Rect channelRect = new Rect(left + displayState.drawStartOffsetInPixels, top, width - displayState.drawStartOffsetInPixels, height);

        // Draw the beat markers before the actual audio content.
        //  NOTE: This contains GUI code.  EveytType.Repaint optimizations handled internally.
        DrawBeatLines(contentRect, displayState, koreo);

        // Only process this drawing if we're repainting (DOES NOT USE GUI SYSTEM).
        if (Event.current.type.Equals(EventType.Repaint))
        {
            // Draw Channels (waveforms)
            for (int i = 0; i < channelDisplays.Count; ++i)
            {
                channelRect.y += i * height;

                // Draw ZERO Line
                Handles.color = new Color(0f, 0f, 0f, KoreographerColors.HandleFullAlpha);
                Handles.DrawLine(new Vector2(channelRect.x, channelRect.center.y), new Vector2(channelRect.x + channelRect.width, channelRect.center.y));

                // Draw Channel Content
                channelDisplays[i].Draw(channelRect, displayState);
            }
        }

        // Draw Tracks (events)
        if (trackDisplay.EventTrack != null)
        {
            Rect trackRect = new Rect(channelRect.x,
                                      contentRect.center.y - 12f,
                                      channelRect.width,
                                      24f);

            trackDisplay.Draw(trackRect, displayState, selectedEvents);
        }

        // Only process this drawing if we're repainting (DOES NOT USE GUI SYSTEM).
        if (Event.current.type.Equals(EventType.Repaint) && bShowPlayhead)
        {
            // Draw overlays
            if (displayState.playheadSamplePosition >= displayState.firstSamplePackToDraw &&
                displayState.playheadSamplePosition <= displayState.firstSamplePackToDraw + (width * displayState.samplesPerPixel))
            {
                // Make the playhead position flexible to allow for scrolling (while maintaining playhead position).
                int position = displayState.drawStartOffsetInPixels + ((displayState.playheadSamplePosition - displayState.firstSamplePackToDraw) / displayState.samplesPerPixel);
                DrawPlayheadLine((int)left + position, (int)top, (int)(top + (2f * height)));
            }
        }

        if (Event.current.type == EventType.Repaint)
        {
            // Store rect.  This must be done during Repaint as the values are not properly handled on Layout.
            waveContentRect = displayRect;
        }

        GUI.EndGroup();
    }
Example #7
0
    void DrawBeatLinesForSection(Rect contentRect, WaveDisplayState displayState, TempoSectionDef tempoSection, int startSample, int endSample, Color sectionColor)
    {
        // Only draw the lines if our current zoom level is reasonable.
        if (tempoSection.SamplesPerBeat >= displayState.samplesPerPixel * 2)		// Check that we will not just be drawing a line (or multiple lines!) for each pixel.  Require at least one gap.
        {
            // Draw our background box.
            {
                Color bgColor = GUI.backgroundColor;
                GUI.backgroundColor = sectionColor;
                Rect boxRect = new Rect(contentRect);
                boxRect.xMin += (float)(startSample - displayState.firstSamplePackToDraw) / displayState.samplesPerPixel;
                boxRect.xMax -= contentRect.width - (float)(endSample - displayState.firstSamplePackToDraw) / displayState.samplesPerPixel;
                GUI.Box(boxRect, "");
                GUI.backgroundColor = bgColor;
            }

            if (Event.current.type.Equals(EventType.Repaint))
            {
                // Set us up to draw the first beat.  Initially, assume we start somewhere within the view.
                float lineLoc = (float)tempoSection.StartSample - displayState.firstSamplePackToDraw;
                int beatNum = 0;

                // Get us onto the current beat boundary if our content begins beyond that first beat.
                if (startSample > tempoSection.StartSample)
                {
                    lineLoc %= tempoSection.SamplesPerBeat;
                    beatNum = ((int)((float)(startSample - tempoSection.StartSample) / tempoSection.SamplesPerBeat));
                }

                float grayValue = 170f / 255f;
                Color firstBeatColor = new Color(grayValue, grayValue, grayValue, KoreographerColors.HandleFullAlpha);

                grayValue = 96f / 255f;
                Color normalBeatColor = new Color(grayValue, grayValue, grayValue, KoreographerColors.HandleFullAlpha);

                // Draw all the beat lines!
                for (; lineLoc < (float)endSample - displayState.firstSamplePackToDraw; lineLoc += tempoSection.SamplesPerBeat)
                {
                    int x = (int)(contentRect.x + (lineLoc / displayState.samplesPerPixel));
                    Handles.color = (beatNum % tempoSection.BeatsPerMeasure == 0) ? firstBeatColor : normalBeatColor;
                    Handles.DrawLine(new Vector2(x, contentRect.yMin), new Vector2(x, contentRect.yMax));

                    // Increment the beat count!
                    beatNum++;
                }
            }
        }
    }
Example #8
0
    void DrawBeatLines(Rect contentRect, WaveDisplayState displayState, Koreography koreo)
    {
        int startSample = displayState.firstSamplePackToDraw;
        int endSample = startSample + displayState.samplesPerPixel * (int)contentRect.width;

        int startSectionIdx = koreo.GetTempoSectionIndexForSample(startSample);
        int endSectionIdx = koreo.GetTempoSectionIndexForSample(endSample);

        TempoSectionDef drawSection = koreo.GetTempoSectionAtIndex(startSectionIdx);
        if (startSectionIdx < endSectionIdx)
        {
            // Multiple sections to draw!
            for (int i = startSectionIdx + 1; i <= endSectionIdx; ++i)
            {
                TempoSectionDef nextSection = koreo.GetTempoSectionAtIndex(i);

                DrawBeatLinesForSection(contentRect, displayState, drawSection, startSample, nextSection.StartSample, sectionBGColors[(i - 1) % sectionBGColors.Length]);

                // Set up for the next section!
                startSample = nextSection.StartSample;
                drawSection = nextSection;
            }
        }

        // Draw the lines for the final (or only) section.
        DrawBeatLinesForSection(contentRect, displayState, drawSection, startSample, endSample, sectionBGColors[endSectionIdx % sectionBGColors.Length]);
    }
Example #9
0
    public int GetSamplePositionOfPoint(Vector2 loc, WaveDisplayState displayState)
    {
        float drawStart = GetDrawStart(displayState);
        float distFromContentStart = loc.x - waveContentRect.x;

        int samplePos = displayState.firstSamplePackToDraw + displayState.samplesPerPixel * (int)(distFromContentStart - drawStart);

        // Disallow negative numbers!
        return Mathf.Max(samplePos, 0);
    }
Example #10
0
 public float GetHorizontalLocOfSample(int samplePos, WaveDisplayState displayState)
 {
     float pixelsIn = (float)(samplePos - displayState.firstSamplePackToDraw) / (float)displayState.samplesPerPixel;
     return pixelsIn + GetDrawStart(displayState);
 }
Example #11
0
    public void Draw(Rect displayRect, WaveDisplayState displayState, List<KoreographyEvent> selectedEvents)
    {
        if (eventTrack != null)
        {
            int rangeStart = displayState.firstSamplePackToDraw;
            int rangeEnd = rangeStart + ((int)displayRect.width * displayState.samplesPerPixel);

            List<KoreographyEvent> drawEvents = eventTrack.GetEventsInRange(rangeStart, rangeEnd);

            // In case we want to change things later.
            Rect eventRect = new Rect(displayRect);
            int xStart, xEnd;	// Range [0, displayRect.width].  These are offsets from displayRect.x!

            if (Event.current.type == EventType.Repaint)
            {
                eventDisplays.Clear();
            }

            foreach (KoreographyEvent e in drawEvents)
            {
                // Sample-space to pixel-space.
                xStart = (e.StartSample - rangeStart) / displayState.samplesPerPixel;

                xEnd = (e.EndSample - rangeStart) / displayState.samplesPerPixel;

                eventRect.xMin = displayRect.x + xStart;
                eventRect.xMax = displayRect.x + xEnd;

                EventDisplay.ValidateDisplayRect(ref eventRect);
                EventDisplay.Draw(eventRect, eventTrack, e, selectedEvents.Contains(e));

                // Do this only during Repaint to cut down on extra processing.
                if (Event.current.type == EventType.Repaint)
                {
                    // Add a little bit to either side.
                    eventRect.width += 3f;
                    eventRect.x -= 1.5f;

                    Rect[] rectSet;

                    if (e.IsOneOff() || eventRect.width <= 12f)
                    {
                        // Switch between resize and move modes.
                        if (Event.current.alt)
                        {
                            Rect leftRect = new Rect(eventRect);
                            Rect rightRect = new Rect(eventRect);

                            leftRect.xMax = leftRect.center.x;
                            rightRect.xMin = rightRect.center.x;

                            EditorGUIUtility.AddCursorRect(leftRect, MouseCursor.ResizeHorizontal);
                            EditorGUIUtility.AddCursorRect(rightRect, MouseCursor.ResizeHorizontal);

                            rectSet = new Rect[4]{eventRect, leftRect, rightRect, new Rect()};
                        }
                        else
                        {
                            // Default to move only.
                            EditorGUIUtility.AddCursorRect(eventRect, MouseCursor.MoveArrow);

                            rectSet = new Rect[4]{eventRect, new Rect(), new Rect(), eventRect};
                        }
                    }
                    else
                    {
                        // Cursor Left:
                        Rect leftRect = new Rect(eventRect);
                        Rect centRect = new Rect(eventRect);
                        Rect rightRect = new Rect(eventRect);

                        float resizeRectWidth = 3f;

                        leftRect.xMax = leftRect.xMin + resizeRectWidth;
                        rightRect.xMin = rightRect.xMax - resizeRectWidth;

                        // Etc.
                        centRect.xMin = leftRect.xMax;
                        centRect.xMax = rightRect.xMin;

                        EditorGUIUtility.AddCursorRect(leftRect, MouseCursor.ResizeHorizontal);
                        EditorGUIUtility.AddCursorRect(rightRect, MouseCursor.ResizeHorizontal);
                        EditorGUIUtility.AddCursorRect(centRect, MouseCursor.MoveArrow);

                        // Store the rects!
                        rectSet = new Rect[4]{eventRect, leftRect, rightRect, centRect};
                    }

                    eventDisplays[e] = rectSet;
                }
            }

            if (Event.current.type == EventType.Repaint)
            {
                // Store our rect.
                trackContentRect = displayRect;
            }
        }
    }