const ResizableBorderComponent::Zone ResizableBorderComponent::Zone::fromPositionOnBorder (const Rectangle<int>& totalSize,
                                                                                           const BorderSize<int>& border,
                                                                                           const Point<int>& position)
{
    int z = 0;

    if (totalSize.contains (position)
         && ! border.subtractedFrom (totalSize).contains (position))
    {
        const int minW = jmax (totalSize.getWidth() / 10, jmin (10, totalSize.getWidth() / 3));
        if (position.x < jmax (border.getLeft(), minW) && border.getLeft() > 0)
            z |= left;
        else if (position.x >= totalSize.getWidth() - jmax (border.getRight(), minW) && border.getRight() > 0)
            z |= right;

        const int minH = jmax (totalSize.getHeight() / 10, jmin (10, totalSize.getHeight() / 3));
        if (position.y < jmax (border.getTop(), minH) && border.getTop() > 0)
            z |= top;
        else if (position.y >= totalSize.getHeight() - jmax (border.getBottom(), minH) && border.getBottom() > 0)
            z |= bottom;
    }

    return Zone (z);
}
void GraphComponent::setNodeDisplayName(BasePlugin* plugin, GraphNodeComponent* node, const String& newName)
{
   plugin->setInstanceName(newName);
   node->setText(newName);

   int w = plugin->getIntValue (PROP_GRAPHWSIZE, defaultNodeWidth);
   int h = plugin->getIntValue (PROP_GRAPHHSIZE, defaultNodeHeight);
   int numIns = plugin->getNumInputs () + plugin->getNumMidiInputs ();
   int numOuts = plugin->getNumOutputs () + plugin->getNumMidiOutputs ();

   if (leftToRight)
   {
      h = jmax (h, (jmax (numIns, numOuts) + 1) * 16);

      const int textHeight = currentFont.getStringWidth (plugin->getInstanceName());
      h = jmax (h, 16 + jmin (textHeight, 300));
   }
   else
   {
      w = jmax (w, (jmax (numIns, numOuts) + 1) * 16);

      const int textWidth = currentFont.getStringWidth (plugin->getInstanceName());
      w = jmax (w, 16 + jmin (textWidth, 300));
   }

   int wSize = w;
   if (wSize < 0) wSize = defaultNodeWidth;
   int hSize = h;
   if (hSize < 0) hSize = defaultNodeHeight;
   String pluginTooltip = plugin->getInstanceName ();
   node->setTooltip (pluginTooltip);
   plugin->setValue (PROP_GRAPHWSIZE, wSize);
   plugin->setValue (PROP_GRAPHHSIZE, hSize);
   node->setSize (wSize, hSize);

}
Example #3
0
//==============================================================================
void CPUInformation::initialise() noexcept
{
    numCpus = jmax ((int) 1, (int) sysconf (_SC_NPROCESSORS_ONLN));
}
bool BufferingAudioSource::readNextBufferChunk()
{
    int64 newBVS, newBVE, sectionToReadStart, sectionToReadEnd;

    {
        const ScopedLock sl (bufferStartPosLock);

        if (wasSourceLooping != isLooping())
        {
            wasSourceLooping = isLooping();
            bufferValidStart = 0;
            bufferValidEnd = 0;
        }

        newBVS = jmax ((int64) 0, nextPlayPos);
        newBVE = newBVS + buffer.getNumSamples() - 4;
        sectionToReadStart = 0;
        sectionToReadEnd = 0;

        const int maxChunkSize = 2048;

        if (newBVS < bufferValidStart || newBVS >= bufferValidEnd)
        {
            newBVE = jmin (newBVE, newBVS + maxChunkSize);

            sectionToReadStart = newBVS;
            sectionToReadEnd = newBVE;

            bufferValidStart = 0;
            bufferValidEnd = 0;
        }
        else if (std::abs ((int) (newBVS - bufferValidStart)) > 512
                  || std::abs ((int) (newBVE - bufferValidEnd)) > 512)
        {
            newBVE = jmin (newBVE, bufferValidEnd + maxChunkSize);

            sectionToReadStart = bufferValidEnd;
            sectionToReadEnd = newBVE;

            bufferValidStart = newBVS;
            bufferValidEnd = jmin (bufferValidEnd, newBVE);
        }
    }

    if (sectionToReadStart == sectionToReadEnd)
        return false;

    jassert (buffer.getNumSamples() > 0);
    const int bufferIndexStart = (int) (sectionToReadStart % buffer.getNumSamples());
    const int bufferIndexEnd   = (int) (sectionToReadEnd   % buffer.getNumSamples());

    if (bufferIndexStart < bufferIndexEnd)
    {
        readBufferSection (sectionToReadStart,
                           (int) (sectionToReadEnd - sectionToReadStart),
                           bufferIndexStart);
    }
    else
    {
        const int initialSize = buffer.getNumSamples() - bufferIndexStart;

        readBufferSection (sectionToReadStart,
                           initialSize,
                           bufferIndexStart);

        readBufferSection (sectionToReadStart + initialSize,
                           (int) (sectionToReadEnd - sectionToReadStart) - initialSize,
                           0);
    }

    {
        const ScopedLock sl2 (bufferStartPosLock);

        bufferValidStart = newBVS;
        bufferValidEnd = newBVE;
    }

    bufferReadyEvent.signal();

    return true;
}
void CodeDocument::remove (const int startPos, const int endPos, const bool undoable)
{
    if (endPos <= startPos)
        return;

    if (undoable)
    {
        undoManager.perform (new CodeDocumentDeleteAction (*this, startPos, endPos));
    }
    else
    {
        Position startPosition (this, startPos);
        Position endPosition (this, endPos);

        maximumLineLength = -1;
        const int firstAffectedLine = startPosition.getLineNumber();
        const int endLine = endPosition.getLineNumber();
        int lastAffectedLine = firstAffectedLine + 1;
        CodeDocumentLine* const firstLine = lines.getUnchecked (firstAffectedLine);

        if (firstAffectedLine == endLine)
        {
            firstLine->line = firstLine->line.substring (0, startPosition.getIndexInLine())
                            + firstLine->line.substring (endPosition.getIndexInLine());
            firstLine->updateLength();
        }
        else
        {
            lastAffectedLine = lines.size();

            CodeDocumentLine* const lastLine = lines.getUnchecked (endLine);
            jassert (lastLine != nullptr);

            firstLine->line = firstLine->line.substring (0, startPosition.getIndexInLine())
                                + lastLine->line.substring (endPosition.getIndexInLine());
            firstLine->updateLength();

            int numLinesToRemove = endLine - firstAffectedLine;
            lines.removeRange (firstAffectedLine + 1, numLinesToRemove);
        }

        int i;
        for (i = firstAffectedLine + 1; i < lines.size(); ++i)
        {
            CodeDocumentLine* const l = lines.getUnchecked (i);
            const CodeDocumentLine* const previousLine = lines.getUnchecked (i - 1);
            l->lineStartInFile = previousLine->lineStartInFile + previousLine->lineLength;
        }

        checkLastLineStatus();

        const int totalChars = getNumCharacters();

        for (i = 0; i < positionsToMaintain.size(); ++i)
        {
            CodeDocument::Position* p = positionsToMaintain.getUnchecked(i);

            if (p->getPosition() > startPosition.getPosition())
                p->setPosition (jmax (startPos, p->getPosition() + startPos - endPos));

            if (p->getPosition() > totalChars)
                p->setPosition (totalChars);
        }

        sendListenerChangeMessage (firstAffectedLine, lastAffectedLine);
    }
}
void Sequencer::setNoteLength (int noteLength_)
{
	noteLength = jmax(noteLength_, 1);
}
Example #7
0
//==============================================================================
bool ListBox::keyPressed (const KeyPress& key)
{
    const int numVisibleRows = viewport->getHeight() / getRowHeight();

    const bool multiple = multipleSelection
                            && (lastRowSelected >= 0)
                            && (key.getModifiers().isShiftDown()
                                 || key.getModifiers().isCtrlDown()
                                 || key.getModifiers().isCommandDown());

    if (key.isKeyCode (KeyPress::upKey))
    {
        if (multiple)
            selectRangeOfRows (lastRowSelected, lastRowSelected - 1);
        else
            selectRow (jmax (0, lastRowSelected - 1));
    }
    else if (key.isKeyCode (KeyPress::returnKey)
              && isRowSelected (lastRowSelected))
    {
        if (model != nullptr)
            model->returnKeyPressed (lastRowSelected);
    }
    else if (key.isKeyCode (KeyPress::pageUpKey))
    {
        if (multiple)
            selectRangeOfRows (lastRowSelected, lastRowSelected - numVisibleRows);
        else
            selectRow (jmax (0, jmax (0, lastRowSelected) - numVisibleRows));
    }
    else if (key.isKeyCode (KeyPress::pageDownKey))
    {
        if (multiple)
            selectRangeOfRows (lastRowSelected, lastRowSelected + numVisibleRows);
        else
            selectRow (jmin (totalItems - 1, jmax (0, lastRowSelected) + numVisibleRows));
    }
    else if (key.isKeyCode (KeyPress::homeKey))
    {
        if (multiple && key.getModifiers().isShiftDown())
            selectRangeOfRows (lastRowSelected, 0);
        else
            selectRow (0);
    }
    else if (key.isKeyCode (KeyPress::endKey))
    {
        if (multiple && key.getModifiers().isShiftDown())
            selectRangeOfRows (lastRowSelected, totalItems - 1);
        else
            selectRow (totalItems - 1);
    }
    else if (key.isKeyCode (KeyPress::downKey))
    {
        if (multiple)
            selectRangeOfRows (lastRowSelected, lastRowSelected + 1);
        else
            selectRow (jmin (totalItems - 1, jmax (0, lastRowSelected) + 1));
    }
    else if ((key.isKeyCode (KeyPress::deleteKey) || key.isKeyCode (KeyPress::backspaceKey))
               && isRowSelected (lastRowSelected))
    {
        if (model != nullptr)
            model->deleteKeyPressed (lastRowSelected);
    }
    else if (multiple && key == KeyPress ('a', ModifierKeys::commandModifier, 0))
    {
        selectRangeOfRows (0, std::numeric_limits<int>::max());
    }
    else
    {
        return false;
    }

    return true;
}
void TabbedButtonBar::resized()
{
    int depth = getWidth();
    int length = getHeight();

    if (orientation == TabsAtTop || orientation == TabsAtBottom)
        std::swap (depth, length);

    const int overlap = getLookAndFeel().getTabButtonOverlap (depth)
                            + getLookAndFeel().getTabButtonSpaceAroundImage() * 2;

    int i, totalLength = overlap;
    int numVisibleButtons = tabs.size();

    for (i = 0; i < tabs.size(); ++i)
    {
        TabBarButton* const tb = tabs.getUnchecked(i)->component;

        totalLength += tb->getBestTabLength (depth) - overlap;
        tb->overlapPixels = overlap / 2;
    }

    double scale = 1.0;

    if (totalLength > length)
        scale = jmax (minimumScale, length / (double) totalLength);

    const bool isTooBig = totalLength * scale > length;
    int tabsButtonPos = 0;

    if (isTooBig)
    {
        if (extraTabsButton == nullptr)
        {
            addAndMakeVisible (extraTabsButton = getLookAndFeel().createTabBarExtrasButton());
            extraTabsButton->addListener (behindFrontTab);
            extraTabsButton->setAlwaysOnTop (true);
            extraTabsButton->setTriggeredOnMouseDown (true);
        }

        const int buttonSize = jmin (proportionOfWidth (0.7f), proportionOfHeight (0.7f));
        extraTabsButton->setSize (buttonSize, buttonSize);

        if (orientation == TabsAtTop || orientation == TabsAtBottom)
        {
            tabsButtonPos = getWidth() - buttonSize / 2 - 1;
            extraTabsButton->setCentrePosition (tabsButtonPos, getHeight() / 2);
        }
        else
        {
            tabsButtonPos = getHeight() - buttonSize / 2 - 1;
            extraTabsButton->setCentrePosition (getWidth() / 2, tabsButtonPos);
        }

        totalLength = 0;

        for (i = 0; i < tabs.size(); ++i)
        {
            TabBarButton* const tb = tabs.getUnchecked(i)->component;

            const int newLength = totalLength + tb->getBestTabLength (depth);

            if (i > 0 && newLength * minimumScale > tabsButtonPos)
            {
                totalLength += overlap;
                break;
            }

            numVisibleButtons = i + 1;
            totalLength = newLength - overlap;
        }

        scale = jmax (minimumScale, tabsButtonPos / (double) totalLength);
    }
    else
    {
        extraTabsButton = nullptr;
    }

    int pos = 0;

    TabBarButton* frontTab = nullptr;

    for (i = 0; i < tabs.size(); ++i)
    {
        TabBarButton* const tb = getTabButton (i);

        if (tb != nullptr)
        {
            const int bestLength = roundToInt (scale * tb->getBestTabLength (depth));

            if (i < numVisibleButtons)
            {
                if (orientation == TabsAtTop || orientation == TabsAtBottom)
                    tb->setBounds (pos, 0, bestLength, getHeight());
                else
                    tb->setBounds (0, pos, getWidth(), bestLength);

                tb->toBack();

                if (i == currentTabIndex)
                    frontTab = tb;

                tb->setVisible (true);
            }
            else
            {
                tb->setVisible (false);
            }

            pos += bestLength - overlap;
        }
    }

    behindFrontTab->setBounds (getLocalBounds());

    if (frontTab != nullptr)
    {
        frontTab->toFront (false);
        behindFrontTab->toBehind (frontTab);
    }
}
static String getLinkedFile (const String& file)
{
    HeapBlock<char> buffer (8194);
    const int numBytes = (int) readlink (file.toRawUTF8(), buffer, 8192);
    return String::fromUTF8 (buffer, jmax (0, numBytes));
};
//==============================================================================
void BubbleComponent::setPosition (const Rectangle<int>& rectangleToPointTo)
{
    Rectangle<int> availableSpace (getParentComponent() != nullptr ? getParentComponent()->getLocalBounds()
                                                                   : getParentMonitorArea());
    int x = 0;
    int y = 0;
    int w = 150;
    int h = 30;

    getContentSize (w, h);
    w += 30;
    h += 30;

    const float edgeIndent = 2.0f;
    const int arrowLength = jmin (10, h / 3, w / 3);

    int spaceAbove = ((allowablePlacements & above) != 0) ? jmax (0, rectangleToPointTo.getY() - availableSpace.getY()) : -1;
    int spaceBelow = ((allowablePlacements & below) != 0) ? jmax (0, availableSpace.getBottom() - rectangleToPointTo.getBottom()) : -1;
    int spaceLeft  = ((allowablePlacements & left)  != 0) ? jmax (0, rectangleToPointTo.getX() - availableSpace.getX()) : -1;
    int spaceRight = ((allowablePlacements & right) != 0) ? jmax (0, availableSpace.getRight() - rectangleToPointTo.getRight()) : -1;

    // look at whether the component is elongated, and if so, try to position next to its longer dimension.
    if (rectangleToPointTo.getWidth() > rectangleToPointTo.getHeight() * 2
         && (spaceAbove > h + 20 || spaceBelow > h + 20))
    {
        spaceLeft = spaceRight = 0;
    }
    else if (rectangleToPointTo.getWidth() < rectangleToPointTo.getHeight() / 2
              && (spaceLeft > w + 20 || spaceRight > w + 20))
    {
        spaceAbove = spaceBelow = 0;
    }

    if (jmax (spaceAbove, spaceBelow) >= jmax (spaceLeft, spaceRight))
    {
        x = rectangleToPointTo.getX() + (rectangleToPointTo.getWidth() - w) / 2;
        arrowTipX = w * 0.5f;
        content.setSize (w, h - arrowLength);

        if (spaceAbove >= spaceBelow)
        {
            // above
            y = rectangleToPointTo.getY() - h;
            content.setPosition (0, 0);
            arrowTipY = h - edgeIndent;
            side = 2;
        }
        else
        {
            // below
            y = rectangleToPointTo.getBottom();
            content.setPosition (0, arrowLength);
            arrowTipY = edgeIndent;
            side = 0;
        }
    }
    else
    {
        y = rectangleToPointTo.getY() + (rectangleToPointTo.getHeight() - h) / 2;
        arrowTipY = h * 0.5f;
        content.setSize (w - arrowLength, h);

        if (spaceLeft > spaceRight)
        {
            // on the left
            x = rectangleToPointTo.getX() - w;
            content.setPosition (0, 0);
            arrowTipX = w - edgeIndent;
            side = 3;
        }
        else
        {
            // on the right
            x = rectangleToPointTo.getRight();
            content.setPosition (arrowLength, 0);
            arrowTipX = edgeIndent;
            side = 1;
        }
    }

    setBounds (x, y, w, h);
}
void AudioFormatReader::readMaxLevels (int64 startSampleInFile,
                                       int64 numSamples,
                                       float& lowestLeft, float& highestLeft,
                                       float& lowestRight, float& highestRight)
{
    if (numSamples <= 0)
    {
        lowestLeft = 0;
        lowestRight = 0;
        highestLeft = 0;
        highestRight = 0;
        return;
    }

    const int bufferSize = (int) jmin (numSamples, (int64) 4096);
    HeapBlock<int> tempSpace ((size_t) bufferSize * 2 + 64);

    int* tempBuffer[3];
    tempBuffer[0] = tempSpace.getData();
    tempBuffer[1] = tempSpace.getData() + bufferSize;
    tempBuffer[2] = 0;

    if (usesFloatingPointData)
    {
        float lmin = 1.0e6f;
        float lmax = -lmin;
        float rmin = lmin;
        float rmax = lmax;

        while (numSamples > 0)
        {
            const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
            read (tempBuffer, 2, startSampleInFile, numToDo, false);

            numSamples -= numToDo;
            startSampleInFile += numToDo;

            float bufMin, bufMax;
            findMinAndMax (reinterpret_cast<float*> (tempBuffer[0]), numToDo, bufMin, bufMax);
            lmin = jmin (lmin, bufMin);
            lmax = jmax (lmax, bufMax);

            if (numChannels > 1)
            {
                findMinAndMax (reinterpret_cast<float*> (tempBuffer[1]), numToDo, bufMin, bufMax);
                rmin = jmin (rmin, bufMin);
                rmax = jmax (rmax, bufMax);
            }
        }

        if (numChannels <= 1)
        {
            rmax = lmax;
            rmin = lmin;
        }

        lowestLeft = lmin;
        highestLeft = lmax;
        lowestRight = rmin;
        highestRight = rmax;
    }
    else
    {
        int lmax = std::numeric_limits<int>::min();
        int lmin = std::numeric_limits<int>::max();
        int rmax = std::numeric_limits<int>::min();
        int rmin = std::numeric_limits<int>::max();

        while (numSamples > 0)
        {
            const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
            if (! read (tempBuffer, 2, startSampleInFile, numToDo, false))
                break;

            numSamples -= numToDo;
            startSampleInFile += numToDo;

            for (int j = (int) numChannels; --j >= 0;)
            {
                int bufMin, bufMax;
                findMinAndMax (tempBuffer[j], numToDo, bufMin, bufMax);

                if (j == 0)
                {
                    lmax = jmax (lmax, bufMax);
                    lmin = jmin (lmin, bufMin);
                }
                else
                {
                    rmax = jmax (rmax, bufMax);
                    rmin = jmin (rmin, bufMin);
                }
            }
        }

        if (numChannels <= 1)
        {
            rmax = lmax;
            rmin = lmin;
        }

        lowestLeft = lmin / (float) std::numeric_limits<int>::max();
        highestLeft = lmax / (float) std::numeric_limits<int>::max();
        lowestRight = rmin / (float) std::numeric_limits<int>::max();
        highestRight = rmax / (float) std::numeric_limits<int>::max();
    }
}
        JUCE_COMRESULT DrawGlyphRun (void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE,
                                     DWRITE_GLYPH_RUN const* glyphRun, DWRITE_GLYPH_RUN_DESCRIPTION const* runDescription,
                                     IUnknown* clientDrawingEffect)
        {
            TextLayout* const layout = static_cast<TextLayout*> (clientDrawingContext);

            if (baselineOriginY != lastOriginY)
            {
                lastOriginY = baselineOriginY;
                ++currentLine;

                if (currentLine >= layout->getNumLines())
                {
                    jassert (currentLine == layout->getNumLines());
                    TextLayout::Line* const newLine = new TextLayout::Line();
                    layout->addLine (newLine);
                    newLine->lineOrigin = Point<float> (baselineOriginX, baselineOriginY);
                }
            }

            TextLayout::Line& glyphLine = layout->getLine (currentLine);

            DWRITE_FONT_METRICS dwFontMetrics;
            glyphRun->fontFace->GetMetrics (&dwFontMetrics);

            glyphLine.ascent  = jmax (glyphLine.ascent,  scaledFontSize (dwFontMetrics.ascent,  dwFontMetrics, glyphRun));
            glyphLine.descent = jmax (glyphLine.descent, scaledFontSize (dwFontMetrics.descent, dwFontMetrics, glyphRun));

            String fontFamily, fontStyle;
            getFontFamilyAndStyle (glyphRun, fontFamily, fontStyle);

            TextLayout::Run* const glyphRunLayout = new TextLayout::Run (Range<int> (runDescription->textPosition,
                                                                                     runDescription->textPosition + runDescription->stringLength),
                                                                         glyphRun->glyphCount);
            glyphLine.runs.add (glyphRunLayout);

            glyphRun->fontFace->GetMetrics (&dwFontMetrics);

            const float totalHeight = std::abs ((float) dwFontMetrics.ascent) + std::abs ((float) dwFontMetrics.descent);
            const float fontHeightToEmSizeFactor = (float) dwFontMetrics.designUnitsPerEm / totalHeight;

            glyphRunLayout->font = Font (fontFamily, fontStyle, glyphRun->fontEmSize / fontHeightToEmSizeFactor);
            glyphRunLayout->colour = getColourOf (static_cast<ID2D1SolidColorBrush*> (clientDrawingEffect));

            const Point<float> lineOrigin (layout->getLine (currentLine).lineOrigin);
            float x = baselineOriginX - lineOrigin.x;

            for (UINT32 i = 0; i < glyphRun->glyphCount; ++i)
            {
                const float advance = glyphRun->glyphAdvances[i];

                if ((glyphRun->bidiLevel & 1) != 0)
                    x -= advance;  // RTL text

                glyphRunLayout->glyphs.add (TextLayout::Glyph (glyphRun->glyphIndices[i],
                                                               Point<float> (x, baselineOriginY - lineOrigin.y),
                                                               advance));

                if ((glyphRun->bidiLevel & 1) == 0)
                    x += advance;  // LTR text
            }

            return S_OK;
        }
Example #13
0
    int read (void* buffer, int bytesToRead) override
    {
        if (finished || isError())
            return 0;

        if (isChunked && ! readingChunk)
        {
            if (position >= chunkEnd)
            {
                const ScopedValueSetter<bool> setter (readingChunk, true, false);
                MemoryOutputStream chunkLengthBuffer;
                char c = 0;

                if (chunkEnd > 0)
                {
                    if (read (&c, 1) != 1 || c != '\r'
                         || read (&c, 1) != 1 || c != '\n')
                    {
                        finished = true;
                        return 0;
                    }
                }

                while (chunkLengthBuffer.getDataSize() < 512 && ! (finished || isError()))
                {
                    if (read (&c, 1) != 1)
                    {
                        finished = true;
                        return 0;
                    }

                    if (c == '\r')
                        continue;

                    if (c == '\n')
                        break;

                    chunkLengthBuffer.writeByte (c);
                }

                const int64 chunkSize = chunkLengthBuffer.toString().trimStart().getHexValue64();

                if (chunkSize == 0)
                {
                    finished = true;
                    return 0;
                }

                chunkEnd += chunkSize;
            }

            if (bytesToRead > chunkEnd - position)
                bytesToRead = static_cast<int> (chunkEnd - position);
        }

        fd_set readbits;
        FD_ZERO (&readbits);
        FD_SET (socketHandle, &readbits);

        struct timeval tv;
        tv.tv_sec = jmax (1, timeOutMs / 1000);
        tv.tv_usec = 0;

        if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
            return 0;   // (timeout)

        const int bytesRead = jmax (0, (int) recv (socketHandle, buffer, (size_t) bytesToRead, MSG_WAITALL));
        if (bytesRead == 0)
            finished = true;

        if (! readingChunk)
            position += bytesRead;

        return bytesRead;
    }
void GlyphArrangement::splitLines (const String& text, Font font, int startIndex,
                                   float x, float y, float width, float height, int maximumLines,
                                   float lineWidth, Justification layout, float minimumHorizontalScale)
{
    const int length = text.length();
    const int originalStartIndex = startIndex;
    int numLines = 1;

    if (length <= 12 && ! text.containsAnyOf (" -\t\r\n"))
        maximumLines = 1;

    maximumLines = jmin (maximumLines, length);

    while (numLines < maximumLines)
    {
        ++numLines;

        const float newFontHeight = height / (float) numLines;

        if (newFontHeight < font.getHeight())
        {
            font.setHeight (jmax (8.0f, newFontHeight));

            removeRangeOfGlyphs (startIndex, -1);
            addLineOfText (font, text, x, y);

            lineWidth = glyphs.getReference (glyphs.size() - 1).getRight()
                            - glyphs.getReference (startIndex).getLeft();
        }

        // Try to estimate the point at which there are enough lines to fit the text,
        // allowing for unevenness in the lengths due to differently sized words.
        const float lineLengthUnevennessAllowance = 80.0f;

        if (numLines > (lineWidth + lineLengthUnevennessAllowance) / width || newFontHeight < 8.0f)
            break;
    }

    if (numLines < 1)
        numLines = 1;

    float lineY = y;
    float widthPerLine = lineWidth / numLines;

    for (int line = 0; line < numLines; ++line)
    {
        int i = startIndex;
        float lineStartX = glyphs.getReference (startIndex).getLeft();

        if (line == numLines - 1)
        {
            widthPerLine = width;
            i = glyphs.size();
        }
        else
        {
            while (i < glyphs.size())
            {
                lineWidth = (glyphs.getReference (i).getRight() - lineStartX);

                if (lineWidth > widthPerLine)
                {
                    // got to a point where the line's too long, so skip forward to find a
                    // good place to break it..
                    const int searchStartIndex = i;

                    while (i < glyphs.size())
                    {
                        if ((glyphs.getReference (i).getRight() - lineStartX) * minimumHorizontalScale < width)
                        {
                            if (glyphs.getReference (i).isWhitespace()
                                 || glyphs.getReference (i).getCharacter() == '-')
                            {
                                ++i;
                                break;
                            }
                        }
                        else
                        {
                            // can't find a suitable break, so try looking backwards..
                            i = searchStartIndex;

                            for (int back = 1; back < jmin (7, i - startIndex - 1); ++back)
                            {
                                if (glyphs.getReference (i - back).isWhitespace()
                                     || glyphs.getReference (i - back).getCharacter() == '-')
                                {
                                    i -= back - 1;
                                    break;
                                }
                            }

                            break;
                        }

                        ++i;
                    }

                    break;
                }

                ++i;
            }

            int wsStart = i;
            while (wsStart > 0 && glyphs.getReference (wsStart - 1).isWhitespace())
                --wsStart;

            int wsEnd = i;
            while (wsEnd < glyphs.size() && glyphs.getReference (wsEnd).isWhitespace())
                ++wsEnd;

            removeRangeOfGlyphs (wsStart, wsEnd - wsStart);
            i = jmax (wsStart, startIndex + 1);
        }

        i -= fitLineIntoSpace (startIndex, i - startIndex,
                               x, lineY, width, font.getHeight(), font,
                               layout.getOnlyHorizontalFlags() | Justification::verticallyCentred,
                               minimumHorizontalScale);

        startIndex = i;
        lineY += font.getHeight();

        if (startIndex >= glyphs.size())
            break;
    }

    justifyGlyphs (originalStartIndex, glyphs.size() - originalStartIndex,
                   x, y, width, height, layout.getFlags() & ~Justification::horizontallyJustified);
}
Example #15
0
my::Parameters my::Torus::_sampled(const int & i, const int & j)const throw(std::logic_error, std::invalid_argument)
{
    _preSampled("Torus", "path angle", "tube angle", "[0,imax()-1]", "[0, jmax()-1]", i, imax()-1, j, jmax()-1);

    float pathAngle, tubeAngle;
    float pathAngleStep, tubeAngleStep;

    pathAngleStep = my::Constant::pi / _nbSlices;
    tubeAngleStep = my::Constant::pi / (_nbStacks+1);

    pathAngle = i*pathAngleStep;
    tubeAngle = j*tubeAngleStep;

    return my::Parameters(pathAngle, tubeAngle);
}
Example #16
0
 inline int getPeak() const noexcept
 {
     return jmax (std::abs ((int) values[0]),
                  std::abs ((int) values[1]));
 }
Example #17
0
double AudioThumbnail::getProportionComplete() const noexcept
{
    return jlimit (0.0, 1.0, numSamplesFinished / (double) jmax ((int64) 1, totalSamples));
}
    bool update (CodeDocument& document, int lineNum,
                 CodeDocument::Iterator& source,
                 CodeTokeniser* analyser, const int spacesPerTab,
                 const CodeDocument::Position& selectionStart,
                 const CodeDocument::Position& selectionEnd)
    {
        OwnedArray <SyntaxToken> newTokens;

        if (analyser == 0)
        {
            newTokens.add (new SyntaxToken (document.getLine (lineNum), -1));
        }
        else if (lineNum < document.getNumLines())
        {
            const CodeDocument::Position pos (&document, lineNum, 0);
            createTokens (pos.getPosition(), pos.getLineText(),
                          source, analyser, newTokens);
        }

        replaceTabsWithSpaces (newTokens, spacesPerTab);

        int newHighlightStart = 0;
        int newHighlightEnd = 0;

        if (selectionStart.getLineNumber() <= lineNum && selectionEnd.getLineNumber() >= lineNum)
        {
            const String line (document.getLine (lineNum));

            CodeDocument::Position lineStart (&document, lineNum, 0), lineEnd (&document, lineNum + 1, 0);
            newHighlightStart = indexToColumn (jmax (0, selectionStart.getPosition() - lineStart.getPosition()),
                                               line, spacesPerTab);
            newHighlightEnd = indexToColumn (jmin (lineEnd.getPosition() - lineStart.getPosition(), selectionEnd.getPosition() - lineStart.getPosition()),
                                             line, spacesPerTab);
        }

        if (newHighlightStart != highlightColumnStart || newHighlightEnd != highlightColumnEnd)
        {
            highlightColumnStart = newHighlightStart;
            highlightColumnEnd = newHighlightEnd;
        }
        else
        {
            if (tokens.size() == newTokens.size())
            {
                bool allTheSame = true;

                for (int i = newTokens.size(); --i >= 0;)
                {
                    if (*tokens.getUnchecked(i) != *newTokens.getUnchecked(i))
                    {
                        allTheSame = false;
                        break;
                    }
                }

                if (allTheSame)
                    return false;
            }
        }

        tokens.swapWithArray (newTokens);
        return true;
    }
Example #19
0
 ListBoxRowComponent* getComponentForRow (const int row) const noexcept
 {
     return rows [row % jmax (1, rows.size())];
 }
Example #20
0
int CallOutBox::getBorderSize() const noexcept
{
    return jmax (getLookAndFeel().getCallOutBoxBorderSize (*this), (int) arrowSize);
}
Example #21
0
//==============================================================================
void ListBox::setRowHeight (const int newHeight)
{
    rowHeight = jmax (1, newHeight);
    viewport->setSingleStepSizes (20, rowHeight);
    updateContent();
}
bool SubregionStream::setPosition (int64 newPosition)
{
    return source->setPosition (jmax ((int64) 0, newPosition + startPositionInSourceStream));
}
void Sequencer::processBlock (AudioSampleBuffer& buffer,
                              MidiBuffer& midiMessages)
{
	AudioPlayHead::CurrentPositionInfo pos (pluginAudioProcessor->lastPosInfo);	
	
	// If we aren't playing...
	if (! pos.isPlaying) {
		if (noteOffs.size() > 0) {
			// Send any upcoming note-off events
			Array<NoteOff*> notesToRemove; 
			for (int i = 0; i < noteOffs.size(); i++) {
				int noteNumber = noteOffs[i]->noteNumber;
				MidiMessage m2 = MidiMessage::noteOff (1, noteNumber);
				midiMessages.addEvent (m2, 0);			
				playingNotes.set (noteNumber, false);

				notesToRemove.add (noteOffs[i]);
			}
			for (int i = 0; i < notesToRemove.size(); i++) {
				// Remove the event from the note-off event list
				// (We do this in two steps so that the noteOffs array isn't modified inside a loop)
				noteOffs.removeObject (notesToRemove[i], true);
			}			
		}
		return;
	}
	
	double ppq = pos.ppqPosition;
	double timeInSeconds = pos.timeInSeconds;
	double bpm = pos.bpm;
	//if (primary) {
		SharedState::getInstance()->setPpqPosition (ppq);
		SharedState::getInstance()->setTimeInSeconds (timeInSeconds);
		SharedState::getInstance()->setBpm (bpm);
	//}
	
	/*
	 int numerator = pos.timeSigNumerator;
	 int denominator = pos.timeSigDenominator;
	 
	 const int ppqPerBar = (numerator * 4 / denominator); // e.g. 4 if 4/4
	 const double beats = (fmod (ppq, ppqPerBar) / ppqPerBar) * numerator;
	 
	 const int bar = ((int) ppq) / ppqPerBar + 1;
	 const int beat = ((int) beats) + 1;
	 const int ticks = ((int) (fmod (beats, 1.0) * 960.0));	
	 */
	
	double tickCountPrecise = fmod (ppq * speed * ticksPerCol, getTotalCols() * ticksPerCol);
	tickCount = (int)tickCountPrecise;
	
	lastPlayheadColPrecise = tickCountPrecise / ticksPerCol;
	jassert (lastPlayheadColPrecise >= 0.0)
	jassert (lastPlayheadColPrecise <= 16.0)
	//if (primary) {
		SharedState::getInstance()->setPlayheadColPrecise (lastPlayheadColPrecise);
	//}		
	
	if (tickCount != lastTickCount) {
		lastTickCount = tickCount;
		
		// Check if we should be degrading...
		int panelIndex = pluginAudioProcessor->getPanelIndex();
      int state = SharedState::getInstance()->getState(panelIndex);
      if (state == Panel::DEGRADING_SLOW ||
          state == Panel::DEGRADING_FAST) {
         // degrade at most once per tempo sweep, in column 0
         if (getPlayheadCol() == 0) {
            if (!columnZeroDegradeUpdate) {
               SharedState::getInstance()->degradeStep(panelIndex);
               columnZeroDegradeUpdate = true;
            }
         } else {
            columnZeroDegradeUpdate = false;
         }
      } else {
         columnZeroDegradeUpdate = false;
         if (state == Panel::ACTIVE) {
            if (SharedState::kDegradeAfterInactiveSec > 0 &&
                (SharedState::getInstance()->getLastTouchElapsedMs(panelIndex) >= 
                 SharedState::kDegradeAfterInactiveSec * 1000)) {
               DBG(String(Time::currentTimeMillis()) + " "
                   + "Start degrading panel " + String(panelIndex));
               SharedState::getInstance()->startDegrade(panelIndex);
            }
         }
      }
		
		// Update starfield if necessary
		if (SharedState::getInstance()->getStarFieldActive()) {
         // bug:67 - for production running, we could assert that the following is true:
         //    SharedState::getInstance()->allAttracting()
         // but that won't work if someone turns on the star field by hand via the sequencer GUI
			if (pluginAudioProcessor->getPanelIndex() == 0) {
				SharedState::getInstance()->updateStarField();
			}
		}
		
		bool playCol = false;  // play the current column of notes?
		float velocity = 0.9f;		
		
		// Swing...
		// If we're on an odd column
		if (getPlayheadCol() % 2 != 0) {
			// If we've waited for enough ticks for the swing
			if (tickCount == (getPlayheadCol() * ticksPerCol) + swingTicks) {
				playCol = true;
			}
		} else {
			// Else we're on an even column
			// If we're on the first tick of the column...
			if (tickCount % ticksPerCol == 0) {
				playCol = true;
			}
		}
		
		// Calculate the latency
		double beatsPerSec = bpm * speed * ticksPerCol / 60.0;
		double secPerBeat = 1.0 / beatsPerSec;	
		
		double tickOffset = tickCountPrecise - tickCount;
		int tickOffsetSamples = tickOffset * secPerBeat * sampleRate;
		tickOffsetSamples = jmax (buffer.getNumSamples() - tickOffsetSamples - 1, 0);
		
		// Send any upcoming note-off events
		Array<NoteOff*> notesToRemove; 
		for (int i = 0; i < noteOffs.size(); i++) {
			if (noteOffs[i]->tick == tickCount) {
				int noteNumber = noteOffs[i]->noteNumber;
				MidiMessage m2 = MidiMessage::noteOff (1, noteNumber);
				midiMessages.addEvent (m2, tickOffsetSamples);			
				playingNotes.set (noteNumber, false);

				notesToRemove.add (noteOffs[i]);
			}
		}
		for (int i = 0; i < notesToRemove.size(); i++) {
			// Remove the event from the note-off event list
			// (We do this in two steps so that the noteOffs array isn't modified inside a loop)
			noteOffs.removeObject (notesToRemove[i], true);
		}		
		
		// If we should play the current column of notes
		if (playCol) {
			int panelIndex = pluginAudioProcessor->getPanelIndex();
			int tabIndex = pluginAudioProcessor->getTabIndex();

			for (int i = 0; i < getTotalRows(); i++) {
				Cell* cell = getCellAt (panelIndex, tabIndex, i, getPlayheadCol());
            if (cell->isOn()) {
               int noteNumber = cell->getNoteNumber();
					// If this note is currently playing
					if (playingNotes[noteNumber] == true) {
						Array<NoteOff*> notesToRemove;
						// Remove any pending note-offs
						for (int j = 0; j < noteOffs.size(); j++) {
							if (noteOffs[j]->noteNumber == noteNumber) {
								notesToRemove.add (noteOffs[j]);
							}
						}
						for (int j = 0; j < notesToRemove.size(); j++) {
							noteOffs.removeObject (notesToRemove[j], true);
						}
						// Send a note-off before retriggering
						MidiMessage m = MidiMessage::noteOff (1, noteNumber);
						midiMessages.addEvent (m, tickOffsetSamples);
						playingNotes.set (noteNumber, false);

					}
					// Play this note
					MidiMessage m = MidiMessage::noteOn (1, noteNumber, velocity);
					midiMessages.addEvent (m, tickOffsetSamples);
					playingNotes.set (noteNumber, true);
					
					// Add an upcoming note-off event
					NoteOff* no;
					noteOffs.add (no = new NoteOff());
					no->tick = (tickCount + noteLength) % (ticksPerCol * getTotalCols());
					no->noteNumber = noteNumber;
				}
			}
		}
	}
}
 void setText (const String& newText)
 {
     document.perform (new SetFocusOrderAction (component, *document.getComponentLayout(), jmax (0, newText.getIntValue())),
                       "Change focus order");
 }
void HighResolutionTimer::startTimer (int periodMs)           { pimpl->start (jmax (1, periodMs)); }
void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelData,
                                                   int numInputChannels,
                                                   float** outputChannelData,
                                                   int numOutputChannels,
                                                   int numSamples)
{
    const ScopedLock sl (audioCallbackLock);

    if (inputLevelMeasurementEnabledCount > 0 && numInputChannels > 0)
    {
        for (int j = 0; j < numSamples; ++j)
        {
            float s = 0;

            for (int i = 0; i < numInputChannels; ++i)
                s += std::abs (inputChannelData[i][j]);

            s /= numInputChannels;

            const double decayFactor = 0.99992;

            if (s > inputLevel)
                inputLevel = s;
            else if (inputLevel > 0.001f)
                inputLevel *= decayFactor;
            else
                inputLevel = 0;
        }
    }
    else
    {
        inputLevel = 0;
    }

    if (callbacks.size() > 0)
    {
        const double callbackStartTime = Time::getMillisecondCounterHiRes();

        tempBuffer.setSize (jmax (1, numOutputChannels), jmax (1, numSamples), false, false, true);

        callbacks.getUnchecked(0)->audioDeviceIOCallback (inputChannelData, numInputChannels,
                                                          outputChannelData, numOutputChannels, numSamples);

        float** const tempChans = tempBuffer.getArrayOfChannels();

        for (int i = callbacks.size(); --i > 0;)
        {
            callbacks.getUnchecked(i)->audioDeviceIOCallback (inputChannelData, numInputChannels,
                                                              tempChans, numOutputChannels, numSamples);

            for (int chan = 0; chan < numOutputChannels; ++chan)
            {
                const float* const src = tempChans [chan];
                float* const dst = outputChannelData [chan];

                if (src != nullptr && dst != nullptr)
                    for (int j = 0; j < numSamples; ++j)
                        dst[j] += src[j];
            }
        }

        const double msTaken = Time::getMillisecondCounterHiRes() - callbackStartTime;
        const double filterAmount = 0.2;
        cpuUsageMs += filterAmount * (msTaken - cpuUsageMs);
    }
    else
    {
        for (int i = 0; i < numOutputChannels; ++i)
            zeromem (outputChannelData[i], sizeof (float) * (size_t) numSamples);
    }

    if (testSound != nullptr)
    {
        const int numSamps = jmin (numSamples, testSound->getNumSamples() - testSoundPosition);
        const float* const src = testSound->getSampleData (0, testSoundPosition);

        for (int i = 0; i < numOutputChannels; ++i)
            for (int j = 0; j < numSamps; ++j)
                outputChannelData [i][j] += src[j];

        testSoundPosition += numSamps;
        if (testSoundPosition >= testSound->getNumSamples())
            testSound = nullptr;
    }
}
Example #27
0
void AlertWindow::updateLayout (const bool onlyIncreaseSize)
{
    const int titleH = 24;
    const int iconWidth = 80;

    const Font font (getLookAndFeel().getAlertWindowMessageFont());

    const int wid = jmax (font.getStringWidth (text),
                          font.getStringWidth (getName()));

    const int sw = (int) std::sqrt (font.getHeight() * wid);
    int w = jmin (300 + sw * 2, (int) (getParentWidth() * 0.7f));
    const int edgeGap = 10;
    const int labelHeight = 18;
    int iconSpace = 0;

    AttributedString attributedText;
    attributedText.append (getName(), font.withHeight (font.getHeight() * 1.1f).boldened());

    if (text.isNotEmpty())
        attributedText.append ("\n\n" + text, font);

    attributedText.setColour (findColour (textColourId));

    if (alertIconType == NoIcon)
    {
        attributedText.setJustification (Justification::centredTop);
        textLayout.createLayoutWithBalancedLineLengths (attributedText, (float) w);
    }
    else
    {
        attributedText.setJustification (Justification::topLeft);
        textLayout.createLayoutWithBalancedLineLengths (attributedText, (float) w);
        iconSpace = iconWidth;
    }

    w = jmax (350, (int) textLayout.getWidth() + iconSpace + edgeGap * 4);
    w = jmin (w, (int) (getParentWidth() * 0.7f));

    const int textLayoutH = (int) textLayout.getHeight();
    const int textBottom = 16 + titleH + textLayoutH;
    int h = textBottom;

    int buttonW = 40;
    int i;
    for (i = 0; i < buttons.size(); ++i)
        buttonW += 16 + buttons.getUnchecked(i)->getWidth();

    w = jmax (buttonW, w);

    h += (textBoxes.size() + comboBoxes.size() + progressBars.size()) * 50;

    if (buttons.size() > 0)
        h += 20 + buttons.getUnchecked(0)->getHeight();

    for (i = customComps.size(); --i >= 0;)
    {
        Component* c = customComps.getUnchecked(i);
        w = jmax (w, (c->getWidth() * 100) / 80);
        h += 10 + c->getHeight();

        if (c->getName().isNotEmpty())
            h += labelHeight;
    }

    for (i = textBlocks.size(); --i >= 0;)
    {
        const AlertTextComp* const ac = static_cast <const AlertTextComp*> (textBlocks.getUnchecked(i));
        w = jmax (w, ac->getPreferredWidth());
    }

    w = jmin (w, (int) (getParentWidth() * 0.7f));

    for (i = textBlocks.size(); --i >= 0;)
    {
        AlertTextComp* const ac = static_cast <AlertTextComp*> (textBlocks.getUnchecked(i));
        ac->updateLayout ((int) (w * 0.8f));
        h += ac->getHeight() + 10;
    }

    h = jmin (getParentHeight() - 50, h);

    if (onlyIncreaseSize)
    {
        w = jmax (w, getWidth());
        h = jmax (h, getHeight());
    }

    if (! isVisible())
    {
        centreAroundComponent (associatedComponent, w, h);
    }
    else
    {
        const int cx = getX() + getWidth() / 2;
        const int cy = getY() + getHeight() / 2;

        setBounds (cx - w / 2,
                   cy - h / 2,
                   w, h);
    }

    textArea.setBounds (edgeGap, edgeGap, w - (edgeGap * 2), h - edgeGap);

    const int spacer = 16;
    int totalWidth = -spacer;

    for (i = buttons.size(); --i >= 0;)
        totalWidth += buttons.getUnchecked(i)->getWidth() + spacer;

    int x = (w - totalWidth) / 2;
    int y = (int) (getHeight() * 0.95f);

    for (i = 0; i < buttons.size(); ++i)
    {
        TextButton* const c = buttons.getUnchecked(i);
        int ny = proportionOfHeight (0.95f) - c->getHeight();
        c->setTopLeftPosition (x, ny);
        if (ny < y)
            y = ny;

        x += c->getWidth() + spacer;

        c->toFront (false);
    }

    y = textBottom;

    for (i = 0; i < allComps.size(); ++i)
    {
        Component* const c = allComps.getUnchecked(i);
        h = 22;

        const int comboIndex = comboBoxes.indexOf (dynamic_cast <ComboBox*> (c));
        if (comboIndex >= 0 && comboBoxNames [comboIndex].isNotEmpty())
            y += labelHeight;

        const int tbIndex = textBoxes.indexOf (dynamic_cast <TextEditor*> (c));
        if (tbIndex >= 0 && textboxNames[tbIndex].isNotEmpty())
            y += labelHeight;

        if (customComps.contains (c))
        {
            if (c->getName().isNotEmpty())
                y += labelHeight;

            c->setTopLeftPosition (proportionOfWidth (0.1f), y);
            h = c->getHeight();
        }
        else if (textBlocks.contains (c))
        {
            c->setTopLeftPosition ((getWidth() - c->getWidth()) / 2, y);
            h = c->getHeight();
        }
        else
        {
            c->setBounds (proportionOfWidth (0.1f), y, proportionOfWidth (0.8f), h);
        }

        y += h + 10;
    }

    setWantsKeyboardFocus (getNumChildComponents() == 0);
}
Example #28
0
void CodeDocument::remove (const int startPos, const int endPos, const bool undoable)
{
    if (endPos <= startPos)
        return;

    if (undoable)
    {
        undoManager.perform (new CodeDocumentDeleteAction (*this, startPos, endPos));
    }
    else
    {
        Position startPosition (*this, startPos);
        Position endPosition (*this, endPos);

        maximumLineLength = -1;
        const int firstAffectedLine = startPosition.getLineNumber();
        const int endLine = endPosition.getLineNumber();
        CodeDocumentLine& firstLine = *lines.getUnchecked (firstAffectedLine);

        if (firstAffectedLine == endLine)
        {
            firstLine.line = firstLine.line.substring (0, startPosition.getIndexInLine())
                           + firstLine.line.substring (endPosition.getIndexInLine());
            firstLine.updateLength();
        }
        else
        {
            CodeDocumentLine& lastLine = *lines.getUnchecked (endLine);

            firstLine.line = firstLine.line.substring (0, startPosition.getIndexInLine())
                            + lastLine.line.substring (endPosition.getIndexInLine());
            firstLine.updateLength();

            int numLinesToRemove = endLine - firstAffectedLine;
            lines.removeRange (firstAffectedLine + 1, numLinesToRemove);
        }

        for (int i = firstAffectedLine + 1; i < lines.size(); ++i)
        {
            CodeDocumentLine& l = *lines.getUnchecked (i);
            const CodeDocumentLine& previousLine = *lines.getUnchecked (i - 1);
            l.lineStartInFile = previousLine.lineStartInFile + previousLine.lineLength;
        }

        checkLastLineStatus();

        const int totalChars = getNumCharacters();

        for (int i = 0; i < positionsToMaintain.size(); ++i)
        {
            CodeDocument::Position& p = *positionsToMaintain.getUnchecked(i);

            if (p.getPosition() > startPosition.getPosition())
                p.setPosition (jmax (startPos, p.getPosition() + startPos - endPos));

            if (p.getPosition() > totalChars)
                p.setPosition (totalChars);
        }

        listeners.call (&CodeDocument::Listener::codeDocumentTextDeleted, startPos, endPos);
    }
}
Example #29
0
 void mouseDrag (const MouseEvent& e) override
 {
     if (canMoveTransport())
         transportSource.setPosition (jmax (0.0, xToTime ((float) e.x)));
 }
Example #30
0
    bool refillCache (const int numSamples, double startTime, const double endTime,
                      const double rate, const int numChans, const int sampsPerThumbSample,
                      LevelDataSource* levelData, const OwnedArray<ThumbData>& chans)
    {
        const double timePerPixel = (endTime - startTime) / numSamples;

        if (numSamples <= 0 || timePerPixel <= 0.0 || rate <= 0)
        {
            invalidate();
            return false;
        }

        if (numSamples == numSamplesCached
             && numChannelsCached == numChans
             && startTime == cachedStart
             && timePerPixel == cachedTimePerPixel
             && ! cacheNeedsRefilling)
        {
            return ! cacheNeedsRefilling;
        }

        numSamplesCached = numSamples;
        numChannelsCached = numChans;
        cachedStart = startTime;
        cachedTimePerPixel = timePerPixel;
        cacheNeedsRefilling = false;

        ensureSize (numSamples);

        if (timePerPixel * rate <= sampsPerThumbSample && levelData != nullptr)
        {
            int sample = roundToInt (startTime * rate);
            Array<float> levels;

            int i;
            for (i = 0; i < numSamples; ++i)
            {
                const int nextSample = roundToInt ((startTime + timePerPixel) * rate);

                if (sample >= 0)
                {
                    if (sample >= levelData->lengthInSamples)
                        break;

                    levelData->getLevels (sample, jmax (1, nextSample - sample), levels);

                    const int totalChans = jmin (levels.size() / 2, numChannelsCached);

                    for (int chan = 0; chan < totalChans; ++chan)
                        getData (chan, i)->setFloat (levels.getUnchecked (chan * 2),
                                                     levels.getUnchecked (chan * 2 + 1));
                }

                startTime += timePerPixel;
                sample = nextSample;
            }

            numSamplesCached = i;
        }
        else
        {
            jassert (chans.size() == numChannelsCached);

            for (int channelNum = 0; channelNum < numChannelsCached; ++channelNum)
            {
                ThumbData* channelData = chans.getUnchecked (channelNum);
                MinMaxValue* cacheData = getData (channelNum, 0);

                const double timeToThumbSampleFactor = rate / (double) sampsPerThumbSample;

                startTime = cachedStart;
                int sample = roundToInt (startTime * timeToThumbSampleFactor);

                for (int i = numSamples; --i >= 0;)
                {
                    const int nextSample = roundToInt ((startTime + timePerPixel) * timeToThumbSampleFactor);

                    channelData->getMinMax (sample, nextSample, *cacheData);

                    ++cacheData;
                    startTime += timePerPixel;
                    sample = nextSample;
                }
            }
        }

        return true;
    }