Draw waveform is too slow

Hi,
I’m trying to draw a waveform using the tracktion SmartThumbnail.
To take care of the zoom i store in an EditViewState two variables ( viewX1 and viewX2 ) that match the left visibile view time and the right visible view time.

I’ve also a TrackComponent where that displays the ClipComponent on the screen in this way :


auto pos = clip->getPosition();

int x1 = editViewState.timeToX(pos.getStart().inSeconds(), getWidth(), viewX1 , viewX2); 
int x2 = editViewState.timeToX(pos.getEnd().inSeconds(), getWidth(), viewX1 , viewX2);


if (clipComp) {
	clipComp->setBounds(x1, 0, x2 - x1, getHeight());
}

In the paint() of the clipComponent :

void AudioClipComponent::paint(Graphics& g)
{

	if (editViewState.drawWaveforms && thumbnail != nullptr)
		drawWaveform(g, *getWaveAudioClip(), *thumbnail, Colours::black.withAlpha(0.5f),
			getX(), getWidth(), getY(), getHeight(), 0);

}
void AudioClipComponent::drawWaveform(Graphics& g, te::AudioClipBase& c, te::SmartThumbnail& thumb, Colour colour, int left, int right, int y, int h, int xOffset) {

			auto getTimeRangeForDrawing = [this](const int l, const int r) -> tracktion::TimeRange
			{
				if (auto p = findParentComponentOfClass<TrackComponent>())
				{
					auto t1 = editViewState.xToTime(l, p->getWidth(),viewX1,viewX2,true);
					auto t2 = editViewState.xToTime(r, p->getWidth(), viewX1, viewX2,true);

					return { TimePosition::fromSeconds( t1 ), TimeDuration::fromSeconds( t2 )};
				}

				return {};
			};

			jassert(left <= right);
			const auto gain = c.getGain();
			const auto pan = thumb.getNumChannels() == 1 ? 0.0f : c.getPan();

			const float pv = pan * gain;
			const float gainL = (gain - pv);
			const float gainR = (gain + pv);

			const bool usesTimeStretchedProxy = c.usesTimeStretchedProxy();

			const auto clipPos = c.getPosition();
			auto offset = clipPos.getOffset();
			auto speedRatio = c.getSpeedRatio();

			g.setColour(colour);

			if (usesTimeStretchedProxy)
			{
				const Rectangle<int> area(left + xOffset, y, right - left, h);

				if (!thumb.isOutOfDate())
				{
					drawChannels(g, thumb, area, false,
						getTimeRangeForDrawing(left, right),
						c.isLeftChannelActive(), c.isRightChannelActive(),
						gainL, gainR);
				}
			}
			else if (c.getLoopLength() == 0s)
			{
				auto region = getTimeRangeForDrawing(left, right);

				auto t1 = (region.getStart() + offset) * speedRatio;
				auto t2 = (region.getEnd() + offset) * speedRatio;

				auto area = Rectangle<int>( left + xOffset, y, right - left, h );
				
				g.reduceClipRegion(area);

				drawChannels(g, thumb,
					area,
					false, { t1, t2 },
					c.isLeftChannelActive(), c.isRightChannelActive(),
					gainL, gainR);
			}

		}

The problem is :
When the clipComponent width is very huge, the drawChannels(…) will call the refillCache(…) method that use the width as numSamples taking so much time.

There is a way to improve performance with a very large zoom ?
@dave96 How did you do in tracktion to make the wraveform drawing so performance ?

Usually your component is only as big as your view of it. When you zoom in, it stays the same size, it just knows what time is at its left and right edge so draw your waveform using those times.

Thanks for the quick respose.
I don’t think to well understand.
What does you mean when you say “When you zoom in, it stays the same size” ?
Are you saying that in the TrackComponent i don’t need to do this :
clipComp->setBounds(x1, 0, x2 - x1, getHeight());
but :
clipComp->setBounds(0, 0, getWidth(), getHeight());
?

Yes. (It can be smaller than you parent width but should get larger).

1 Like

mhhh somethink like that ?
clipComp->setBounds( jmax(0,x1), 0, jmin(x2-x1,getWidth(),) getHeight());

In general it could be smaller that the parent ( TrackComponent ) width an not larger ?

Yeah. You need to think of it as a “view” on to the the clip, not the whole clip.

2 Likes