mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-02-05 03:50:07 +00:00
Fixed a very very subtle component bug. Added peak level detection to AudioThumbnail. Tidied up some old demo plugin UI code.
This commit is contained in:
parent
4d6b2daa93
commit
098abe4a2f
11 changed files with 199 additions and 132 deletions
|
|
@ -62,6 +62,12 @@ struct AudioThumbnail::MinMaxValue
|
|||
return maxValue > minValue;
|
||||
}
|
||||
|
||||
inline int getPeak() const throw()
|
||||
{
|
||||
return jmax (std::abs ((int) minValue),
|
||||
std::abs ((int) maxValue));
|
||||
}
|
||||
|
||||
inline void read (InputStream& input)
|
||||
{
|
||||
minValue = input.readByte();
|
||||
|
|
@ -262,6 +268,7 @@ class AudioThumbnail::ThumbData
|
|||
{
|
||||
public:
|
||||
ThumbData (const int numThumbSamples)
|
||||
: peakLevel (-1)
|
||||
{
|
||||
ensureSize (numThumbSamples);
|
||||
}
|
||||
|
|
@ -308,6 +315,8 @@ public:
|
|||
|
||||
void write (const MinMaxValue* const source, const int startIndex, const int numValues)
|
||||
{
|
||||
resetPeak();
|
||||
|
||||
if (startIndex + numValues > data.size())
|
||||
ensureSize (startIndex + numValues);
|
||||
|
||||
|
|
@ -317,8 +326,29 @@ public:
|
|||
dest[i] = source[i];
|
||||
}
|
||||
|
||||
void resetPeak()
|
||||
{
|
||||
peakLevel = -1;
|
||||
}
|
||||
|
||||
int getPeak()
|
||||
{
|
||||
if (peakLevel < 0)
|
||||
{
|
||||
for (int i = 0; i < data.size(); ++i)
|
||||
{
|
||||
const int peak = data[i].getPeak();
|
||||
if (peak > peakLevel)
|
||||
peakLevel = peak;
|
||||
}
|
||||
}
|
||||
|
||||
return peakLevel;
|
||||
}
|
||||
|
||||
private:
|
||||
Array <MinMaxValue> data;
|
||||
int peakLevel;
|
||||
|
||||
void ensureSize (const int thumbSamples)
|
||||
{
|
||||
|
|
@ -700,6 +730,16 @@ bool AudioThumbnail::isFullyLoaded() const throw()
|
|||
return numSamplesFinished >= totalSamples - samplesPerThumbSample;
|
||||
}
|
||||
|
||||
float AudioThumbnail::getApproximatePeak() const
|
||||
{
|
||||
int peak = 0;
|
||||
|
||||
for (int i = channels.size(); --i >= 0;)
|
||||
peak = jmax (peak, channels.getUnchecked(i)->getPeak());
|
||||
|
||||
return jlimit (0, 127, peak) / 127.0f;
|
||||
}
|
||||
|
||||
void AudioThumbnail::drawChannel (Graphics& g, const Rectangle<int>& area, double startTime,
|
||||
double endTime, int channelNum, float verticalZoomFactor)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -177,6 +177,12 @@ public:
|
|||
/** Returns true if the low res preview is fully generated. */
|
||||
bool isFullyLoaded() const throw();
|
||||
|
||||
/** Returns the highest level in the thumbnail.
|
||||
Note that because the thumb only stores low-resolution data, this isn't
|
||||
an accurate representation of the highest value, it's only a rough approximation.
|
||||
*/
|
||||
float getApproximatePeak() const;
|
||||
|
||||
/** Returns the hash code that was set by setSource() or setReader(). */
|
||||
int64 getHashCode() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -546,10 +546,10 @@ public:
|
|||
: graph (graph_),
|
||||
orderedNodes (orderedNodes_)
|
||||
{
|
||||
nodeIds.add (zeroNodeID); // first buffer is read-only zeros
|
||||
nodeIds.add ((uint32) zeroNodeID); // first buffer is read-only zeros
|
||||
channels.add (0);
|
||||
|
||||
midiNodeIds.add (zeroNodeID);
|
||||
midiNodeIds.add ((uint32) zeroNodeID);
|
||||
|
||||
for (int i = 0; i < orderedNodes.size(); ++i)
|
||||
{
|
||||
|
|
@ -835,7 +835,7 @@ private:
|
|||
if (midiNodeIds.getUnchecked(i) == freeNodeID)
|
||||
return i;
|
||||
|
||||
midiNodeIds.add (freeNodeID);
|
||||
midiNodeIds.add ((uint32) freeNodeID);
|
||||
return midiNodeIds.size() - 1;
|
||||
}
|
||||
else
|
||||
|
|
@ -844,7 +844,7 @@ private:
|
|||
if (nodeIds.getUnchecked(i) == freeNodeID)
|
||||
return i;
|
||||
|
||||
nodeIds.add (freeNodeID);
|
||||
nodeIds.add ((uint32) freeNodeID);
|
||||
channels.add (0);
|
||||
return nodeIds.size() - 1;
|
||||
}
|
||||
|
|
@ -884,7 +884,7 @@ private:
|
|||
nodeIds.getUnchecked(i),
|
||||
channels.getUnchecked(i)))
|
||||
{
|
||||
nodeIds.set (i, freeNodeID);
|
||||
nodeIds.set (i, (uint32) freeNodeID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -895,7 +895,7 @@ private:
|
|||
midiNodeIds.getUnchecked(i),
|
||||
AudioProcessorGraph::midiChannelIndex))
|
||||
{
|
||||
midiNodeIds.set (i, freeNodeID);
|
||||
midiNodeIds.set (i, (uint32) freeNodeID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
*/
|
||||
#define JUCE_MAJOR_VERSION 1
|
||||
#define JUCE_MINOR_VERSION 52
|
||||
#define JUCE_BUILDNUMBER 105
|
||||
#define JUCE_BUILDNUMBER 106
|
||||
|
||||
/** Current Juce version number.
|
||||
|
||||
|
|
|
|||
|
|
@ -31,18 +31,19 @@ class InternalTimerThread;
|
|||
|
||||
//==============================================================================
|
||||
/**
|
||||
Repeatedly calls a user-defined method at a specified time interval.
|
||||
Makes repeated callbacks to a virtual method at a specified time interval.
|
||||
|
||||
A Timer's timerCallback() method will be repeatedly called at a given
|
||||
interval. Initially when a Timer object is created, they will do nothing
|
||||
until the startTimer() method is called, then the message thread will
|
||||
start calling it back until stopTimer() is called.
|
||||
interval. When you create a Timer object, it will do nothing until the
|
||||
startTimer() method is called, which will cause the message thread to
|
||||
start making callbacks at the specified interval, until stopTimer() is called
|
||||
or the object is deleted.
|
||||
|
||||
The time interval isn't guaranteed to be precise to any more than maybe
|
||||
10-20ms, and the intervals may end up being much longer than requested if the
|
||||
system is busy. Because it's the message thread that is doing the callbacks,
|
||||
any messages that take a significant amount of time to process will block
|
||||
all the timers for that period.
|
||||
system is busy. Because the callbacks are made by the main message thread,
|
||||
anything that blocks the message queue for a period of time will also prevent
|
||||
any timers from running until it can carry on.
|
||||
|
||||
If you need to have a single callback that is shared by multiple timers with
|
||||
different frequencies, then the MultiTimer class allows you to do that - its
|
||||
|
|
|
|||
|
|
@ -470,8 +470,7 @@ void Component::setVisible (bool shouldBeVisible)
|
|||
|
||||
if (! shouldBeVisible)
|
||||
{
|
||||
if (currentlyFocusedComponent == this
|
||||
|| isParentOf (currentlyFocusedComponent))
|
||||
if (currentlyFocusedComponent == this || isParentOf (currentlyFocusedComponent))
|
||||
{
|
||||
if (parentComponent_ != 0)
|
||||
parentComponent_->grabKeyboardFocus();
|
||||
|
|
@ -1358,32 +1357,18 @@ Component* Component::removeChildComponent (const int index)
|
|||
childComponentList_.remove (index);
|
||||
child->parentComponent_ = 0;
|
||||
|
||||
if (childShowing)
|
||||
// (NB: there are obscure situations where a childShowing = false, but it still has the focus)
|
||||
if (currentlyFocusedComponent == child || child->isParentOf (currentlyFocusedComponent))
|
||||
{
|
||||
JUCE_TRY
|
||||
{
|
||||
if ((currentlyFocusedComponent == child)
|
||||
|| child->isParentOf (currentlyFocusedComponent))
|
||||
{
|
||||
// get rid first to force the grabKeyboardFocus to change to us.
|
||||
giveAwayFocus();
|
||||
grabKeyboardFocus();
|
||||
}
|
||||
}
|
||||
#if JUCE_CATCH_UNHANDLED_EXCEPTIONS
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
currentlyFocusedComponent = 0;
|
||||
Desktop::getInstance().triggerFocusCallback();
|
||||
JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
currentlyFocusedComponent = 0;
|
||||
Desktop::getInstance().triggerFocusCallback();
|
||||
JUCEApplication::sendUnhandledException (0, __FILE__, __LINE__);
|
||||
}
|
||||
#endif
|
||||
SafePointer<Component> thisPointer (this);
|
||||
|
||||
giveAwayFocus();
|
||||
|
||||
if (thisPointer == 0)
|
||||
return child;
|
||||
|
||||
if (childShowing)
|
||||
grabKeyboardFocus();
|
||||
}
|
||||
|
||||
child->internalHierarchyChanged();
|
||||
|
|
@ -2854,14 +2839,13 @@ Component* JUCE_CALLTYPE Component::getCurrentlyFocusedComponent() throw()
|
|||
|
||||
void Component::giveAwayFocus()
|
||||
{
|
||||
// use a copy so we can clear the value before the call
|
||||
SafePointer<Component> componentLosingFocus (currentlyFocusedComponent);
|
||||
|
||||
Component* const componentLosingFocus = currentlyFocusedComponent;
|
||||
currentlyFocusedComponent = 0;
|
||||
Desktop::getInstance().triggerFocusCallback();
|
||||
|
||||
if (componentLosingFocus != 0)
|
||||
componentLosingFocus->internalFocusLoss (focusChangedDirectly);
|
||||
|
||||
Desktop::getInstance().triggerFocusCallback();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -2171,9 +2171,9 @@ private:
|
|||
bool isDisabledFlag : 1;
|
||||
bool childCompFocusedFlag : 1;
|
||||
bool dontClipGraphicsFlag : 1;
|
||||
#if JUCE_DEBUG
|
||||
#if JUCE_DEBUG
|
||||
bool isInsidePaintCall : 1;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
union
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue