| @@ -13,32 +13,38 @@ | |||||
| //============================================================================== | //============================================================================== | ||||
| JuceDemoPluginAudioProcessorEditor::JuceDemoPluginAudioProcessorEditor (JuceDemoPluginAudioProcessor* ownerFilter) | JuceDemoPluginAudioProcessorEditor::JuceDemoPluginAudioProcessorEditor (JuceDemoPluginAudioProcessor* ownerFilter) | ||||
| : AudioProcessorEditor (ownerFilter) | |||||
| : AudioProcessorEditor (ownerFilter), | |||||
| midiKeyboard (ownerFilter->keyboardState, MidiKeyboardComponent::horizontalKeyboard), | |||||
| infoLabel (String::empty), | |||||
| gainLabel ("", "Throughput level:"), | |||||
| delayLabel ("", "Delay:"), | |||||
| gainSlider ("gain"), | |||||
| delaySlider ("delay") | |||||
| { | { | ||||
| addAndMakeVisible (gainSlider = new Slider ("gain")); | |||||
| gainSlider->setSliderStyle (Slider::Rotary); | |||||
| gainSlider->addListener (this); | |||||
| gainSlider->setRange (0.0, 1.0, 0.01); | |||||
| Label* l = new Label ("", "Throughput level:"); | |||||
| l->attachToComponent (gainSlider, false); | |||||
| l->setFont (Font (11.0f)); | |||||
| addAndMakeVisible (delaySlider = new Slider ("delay")); | |||||
| delaySlider->setSliderStyle (Slider::Rotary); | |||||
| delaySlider->addListener (this); | |||||
| delaySlider->setRange (0.0, 1.0, 0.01); | |||||
| l = new Label ("", "Delay:"); | |||||
| l->attachToComponent (delaySlider, false); | |||||
| l->setFont (Font (11.0f)); | |||||
| // create and add the midi keyboard component.. | |||||
| addAndMakeVisible (midiKeyboard | |||||
| = new MidiKeyboardComponent (ownerFilter->keyboardState, | |||||
| MidiKeyboardComponent::horizontalKeyboard)); | |||||
| // add some sliders.. | |||||
| addAndMakeVisible (&gainSlider); | |||||
| gainSlider.setSliderStyle (Slider::Rotary); | |||||
| gainSlider.addListener (this); | |||||
| gainSlider.setRange (0.0, 1.0, 0.01); | |||||
| addAndMakeVisible (&delaySlider); | |||||
| delaySlider.setSliderStyle (Slider::Rotary); | |||||
| delaySlider.addListener (this); | |||||
| delaySlider.setRange (0.0, 1.0, 0.01); | |||||
| // add some labels for the sliders.. | |||||
| gainLabel.attachToComponent (&gainSlider, false); | |||||
| gainLabel.setFont (Font (11.0f)); | |||||
| delayLabel.attachToComponent (&delaySlider, false); | |||||
| delayLabel.setFont (Font (11.0f)); | |||||
| // add the midi keyboard component.. | |||||
| addAndMakeVisible (&midiKeyboard); | |||||
| // add a label that will display the current timecode and status.. | // add a label that will display the current timecode and status.. | ||||
| addAndMakeVisible (infoLabel = new Label (String::empty, String::empty)); | |||||
| infoLabel->setColour (Label::textColourId, Colours::blue); | |||||
| addAndMakeVisible (&infoLabel); | |||||
| infoLabel.setColour (Label::textColourId, Colours::blue); | |||||
| // add the triangular resizer component for the bottom-right of the UI | // add the triangular resizer component for the bottom-right of the UI | ||||
| addAndMakeVisible (resizer = new ResizableCornerComponent (this, &resizeLimits)); | addAndMakeVisible (resizer = new ResizableCornerComponent (this, &resizeLimits)); | ||||
| @@ -53,7 +59,6 @@ JuceDemoPluginAudioProcessorEditor::JuceDemoPluginAudioProcessorEditor (JuceDemo | |||||
| JuceDemoPluginAudioProcessorEditor::~JuceDemoPluginAudioProcessorEditor() | JuceDemoPluginAudioProcessorEditor::~JuceDemoPluginAudioProcessorEditor() | ||||
| { | { | ||||
| deleteAllChildren(); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -65,12 +70,12 @@ void JuceDemoPluginAudioProcessorEditor::paint (Graphics& g) | |||||
| void JuceDemoPluginAudioProcessorEditor::resized() | void JuceDemoPluginAudioProcessorEditor::resized() | ||||
| { | { | ||||
| infoLabel->setBounds (10, 4, 400, 25); | |||||
| gainSlider->setBounds (20, 60, 150, 40); | |||||
| delaySlider->setBounds (200, 60, 150, 40); | |||||
| infoLabel.setBounds (10, 4, 400, 25); | |||||
| gainSlider.setBounds (20, 60, 150, 40); | |||||
| delaySlider.setBounds (200, 60, 150, 40); | |||||
| const int keyboardHeight = 70; | const int keyboardHeight = 70; | ||||
| midiKeyboard->setBounds (4, getHeight() - keyboardHeight - 4, getWidth() - 8, keyboardHeight); | |||||
| midiKeyboard.setBounds (4, getHeight() - keyboardHeight - 4, getWidth() - 8, keyboardHeight); | |||||
| resizer->setBounds (getWidth() - 16, getHeight() - 16, 16, 16); | resizer->setBounds (getWidth() - 16, getHeight() - 16, 16, 16); | ||||
| @@ -89,25 +94,25 @@ void JuceDemoPluginAudioProcessorEditor::timerCallback() | |||||
| if (lastDisplayedPosition != newPos) | if (lastDisplayedPosition != newPos) | ||||
| displayPositionInfo (newPos); | displayPositionInfo (newPos); | ||||
| gainSlider->setValue (ourProcessor->gain, false); | |||||
| delaySlider->setValue (ourProcessor->delay, false); | |||||
| gainSlider.setValue (ourProcessor->gain, false); | |||||
| delaySlider.setValue (ourProcessor->delay, false); | |||||
| } | } | ||||
| // This is our Slider::Listener callback, when the user drags a slider. | // This is our Slider::Listener callback, when the user drags a slider. | ||||
| void JuceDemoPluginAudioProcessorEditor::sliderValueChanged (Slider* slider) | void JuceDemoPluginAudioProcessorEditor::sliderValueChanged (Slider* slider) | ||||
| { | { | ||||
| if (slider == gainSlider) | |||||
| if (slider == &gainSlider) | |||||
| { | { | ||||
| // It's vital to use setParameterNotifyingHost to change any parameters that are automatable | // It's vital to use setParameterNotifyingHost to change any parameters that are automatable | ||||
| // by the host, rather than just modifying them directly, otherwise the host won't know | // by the host, rather than just modifying them directly, otherwise the host won't know | ||||
| // that they've changed. | // that they've changed. | ||||
| getProcessor()->setParameterNotifyingHost (JuceDemoPluginAudioProcessor::gainParam, | getProcessor()->setParameterNotifyingHost (JuceDemoPluginAudioProcessor::gainParam, | ||||
| (float) gainSlider->getValue()); | |||||
| (float) gainSlider.getValue()); | |||||
| } | } | ||||
| else if (slider == delaySlider) | |||||
| else if (slider == &delaySlider) | |||||
| { | { | ||||
| getProcessor()->setParameterNotifyingHost (JuceDemoPluginAudioProcessor::delayParam, | getProcessor()->setParameterNotifyingHost (JuceDemoPluginAudioProcessor::delayParam, | ||||
| (float) delaySlider->getValue()); | |||||
| (float) delaySlider.getValue()); | |||||
| } | } | ||||
| } | } | ||||
| @@ -169,5 +174,5 @@ void JuceDemoPluginAudioProcessorEditor::displayPositionInfo (const AudioPlayHea | |||||
| else if (pos.isPlaying) | else if (pos.isPlaying) | ||||
| displayText << " (playing)"; | displayText << " (playing)"; | ||||
| infoLabel->setText (displayText, false); | |||||
| infoLabel.setText (displayText, false); | |||||
| } | } | ||||
| @@ -34,11 +34,11 @@ public: | |||||
| void sliderValueChanged (Slider*); | void sliderValueChanged (Slider*); | ||||
| private: | private: | ||||
| MidiKeyboardComponent* midiKeyboard; | |||||
| Label* infoLabel; | |||||
| Slider* gainSlider; | |||||
| Slider* delaySlider; | |||||
| ResizableCornerComponent* resizer; | |||||
| MidiKeyboardComponent midiKeyboard; | |||||
| Label infoLabel, gainLabel, delayLabel; | |||||
| Slider gainSlider; | |||||
| Slider delaySlider; | |||||
| ScopedPointer<ResizableCornerComponent> resizer; | |||||
| ComponentBoundsConstrainer resizeLimits; | ComponentBoundsConstrainer resizeLimits; | ||||
| AudioPlayHead::CurrentPositionInfo lastDisplayedPosition; | AudioPlayHead::CurrentPositionInfo lastDisplayedPosition; | ||||
| @@ -21988,6 +21988,12 @@ struct AudioThumbnail::MinMaxValue | |||||
| return maxValue > minValue; | return maxValue > minValue; | ||||
| } | } | ||||
| inline int getPeak() const throw() | |||||
| { | |||||
| return jmax (std::abs ((int) minValue), | |||||
| std::abs ((int) maxValue)); | |||||
| } | |||||
| inline void read (InputStream& input) | inline void read (InputStream& input) | ||||
| { | { | ||||
| minValue = input.readByte(); | minValue = input.readByte(); | ||||
| @@ -22186,6 +22192,7 @@ class AudioThumbnail::ThumbData | |||||
| { | { | ||||
| public: | public: | ||||
| ThumbData (const int numThumbSamples) | ThumbData (const int numThumbSamples) | ||||
| : peakLevel (-1) | |||||
| { | { | ||||
| ensureSize (numThumbSamples); | ensureSize (numThumbSamples); | ||||
| } | } | ||||
| @@ -22232,6 +22239,8 @@ public: | |||||
| void write (const MinMaxValue* const source, const int startIndex, const int numValues) | void write (const MinMaxValue* const source, const int startIndex, const int numValues) | ||||
| { | { | ||||
| resetPeak(); | |||||
| if (startIndex + numValues > data.size()) | if (startIndex + numValues > data.size()) | ||||
| ensureSize (startIndex + numValues); | ensureSize (startIndex + numValues); | ||||
| @@ -22241,8 +22250,29 @@ public: | |||||
| dest[i] = source[i]; | 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: | private: | ||||
| Array <MinMaxValue> data; | Array <MinMaxValue> data; | ||||
| int peakLevel; | |||||
| void ensureSize (const int thumbSamples) | void ensureSize (const int thumbSamples) | ||||
| { | { | ||||
| @@ -22619,6 +22649,16 @@ bool AudioThumbnail::isFullyLoaded() const throw() | |||||
| return numSamplesFinished >= totalSamples - samplesPerThumbSample; | 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, | void AudioThumbnail::drawChannel (Graphics& g, const Rectangle<int>& area, double startTime, | ||||
| double endTime, int channelNum, float verticalZoomFactor) | double endTime, int channelNum, float verticalZoomFactor) | ||||
| { | { | ||||
| @@ -36682,10 +36722,10 @@ public: | |||||
| : graph (graph_), | : graph (graph_), | ||||
| orderedNodes (orderedNodes_) | orderedNodes (orderedNodes_) | ||||
| { | { | ||||
| nodeIds.add (zeroNodeID); // first buffer is read-only zeros | |||||
| nodeIds.add ((uint32) zeroNodeID); // first buffer is read-only zeros | |||||
| channels.add (0); | channels.add (0); | ||||
| midiNodeIds.add (zeroNodeID); | |||||
| midiNodeIds.add ((uint32) zeroNodeID); | |||||
| for (int i = 0; i < orderedNodes.size(); ++i) | for (int i = 0; i < orderedNodes.size(); ++i) | ||||
| { | { | ||||
| @@ -36969,7 +37009,7 @@ private: | |||||
| if (midiNodeIds.getUnchecked(i) == freeNodeID) | if (midiNodeIds.getUnchecked(i) == freeNodeID) | ||||
| return i; | return i; | ||||
| midiNodeIds.add (freeNodeID); | |||||
| midiNodeIds.add ((uint32) freeNodeID); | |||||
| return midiNodeIds.size() - 1; | return midiNodeIds.size() - 1; | ||||
| } | } | ||||
| else | else | ||||
| @@ -36978,7 +37018,7 @@ private: | |||||
| if (nodeIds.getUnchecked(i) == freeNodeID) | if (nodeIds.getUnchecked(i) == freeNodeID) | ||||
| return i; | return i; | ||||
| nodeIds.add (freeNodeID); | |||||
| nodeIds.add ((uint32) freeNodeID); | |||||
| channels.add (0); | channels.add (0); | ||||
| return nodeIds.size() - 1; | return nodeIds.size() - 1; | ||||
| } | } | ||||
| @@ -37018,7 +37058,7 @@ private: | |||||
| nodeIds.getUnchecked(i), | nodeIds.getUnchecked(i), | ||||
| channels.getUnchecked(i))) | channels.getUnchecked(i))) | ||||
| { | { | ||||
| nodeIds.set (i, freeNodeID); | |||||
| nodeIds.set (i, (uint32) freeNodeID); | |||||
| } | } | ||||
| } | } | ||||
| @@ -37029,7 +37069,7 @@ private: | |||||
| midiNodeIds.getUnchecked(i), | midiNodeIds.getUnchecked(i), | ||||
| AudioProcessorGraph::midiChannelIndex)) | AudioProcessorGraph::midiChannelIndex)) | ||||
| { | { | ||||
| midiNodeIds.set (i, freeNodeID); | |||||
| midiNodeIds.set (i, (uint32) freeNodeID); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -40198,8 +40238,7 @@ void Component::setVisible (bool shouldBeVisible) | |||||
| if (! shouldBeVisible) | if (! shouldBeVisible) | ||||
| { | { | ||||
| if (currentlyFocusedComponent == this | |||||
| || isParentOf (currentlyFocusedComponent)) | |||||
| if (currentlyFocusedComponent == this || isParentOf (currentlyFocusedComponent)) | |||||
| { | { | ||||
| if (parentComponent_ != 0) | if (parentComponent_ != 0) | ||||
| parentComponent_->grabKeyboardFocus(); | parentComponent_->grabKeyboardFocus(); | ||||
| @@ -41074,32 +41113,18 @@ Component* Component::removeChildComponent (const int index) | |||||
| childComponentList_.remove (index); | childComponentList_.remove (index); | ||||
| child->parentComponent_ = 0; | 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(); | child->internalHierarchyChanged(); | ||||
| @@ -42545,14 +42570,13 @@ Component* JUCE_CALLTYPE Component::getCurrentlyFocusedComponent() throw() | |||||
| void Component::giveAwayFocus() | 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; | currentlyFocusedComponent = 0; | ||||
| Desktop::getInstance().triggerFocusCallback(); | |||||
| if (componentLosingFocus != 0) | if (componentLosingFocus != 0) | ||||
| componentLosingFocus->internalFocusLoss (focusChangedDirectly); | componentLosingFocus->internalFocusLoss (focusChangedDirectly); | ||||
| Desktop::getInstance().triggerFocusCallback(); | |||||
| } | } | ||||
| bool Component::isMouseOver (const bool includeChildren) const | bool Component::isMouseOver (const bool includeChildren) const | ||||
| @@ -64,7 +64,7 @@ | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 52 | #define JUCE_MINOR_VERSION 52 | ||||
| #define JUCE_BUILDNUMBER 105 | |||||
| #define JUCE_BUILDNUMBER 106 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -28178,9 +28178,9 @@ private: | |||||
| bool isDisabledFlag : 1; | bool isDisabledFlag : 1; | ||||
| bool childCompFocusedFlag : 1; | bool childCompFocusedFlag : 1; | ||||
| bool dontClipGraphicsFlag : 1; | bool dontClipGraphicsFlag : 1; | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| bool isInsidePaintCall : 1; | bool isInsidePaintCall : 1; | ||||
| #endif | |||||
| #endif | |||||
| }; | }; | ||||
| union | union | ||||
| @@ -29126,18 +29126,19 @@ private: | |||||
| class InternalTimerThread; | 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 | 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 | 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 | 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 | 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 | different frequencies, then the MultiTimer class allows you to do that - its | ||||
| @@ -32741,6 +32742,12 @@ public: | |||||
| /** Returns true if the low res preview is fully generated. */ | /** Returns true if the low res preview is fully generated. */ | ||||
| bool isFullyLoaded() const throw(); | 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(). */ | /** Returns the hash code that was set by setSource() or setReader(). */ | ||||
| int64 getHashCode() const; | int64 getHashCode() const; | ||||
| @@ -62,6 +62,12 @@ struct AudioThumbnail::MinMaxValue | |||||
| return maxValue > minValue; | return maxValue > minValue; | ||||
| } | } | ||||
| inline int getPeak() const throw() | |||||
| { | |||||
| return jmax (std::abs ((int) minValue), | |||||
| std::abs ((int) maxValue)); | |||||
| } | |||||
| inline void read (InputStream& input) | inline void read (InputStream& input) | ||||
| { | { | ||||
| minValue = input.readByte(); | minValue = input.readByte(); | ||||
| @@ -262,6 +268,7 @@ class AudioThumbnail::ThumbData | |||||
| { | { | ||||
| public: | public: | ||||
| ThumbData (const int numThumbSamples) | ThumbData (const int numThumbSamples) | ||||
| : peakLevel (-1) | |||||
| { | { | ||||
| ensureSize (numThumbSamples); | ensureSize (numThumbSamples); | ||||
| } | } | ||||
| @@ -308,6 +315,8 @@ public: | |||||
| void write (const MinMaxValue* const source, const int startIndex, const int numValues) | void write (const MinMaxValue* const source, const int startIndex, const int numValues) | ||||
| { | { | ||||
| resetPeak(); | |||||
| if (startIndex + numValues > data.size()) | if (startIndex + numValues > data.size()) | ||||
| ensureSize (startIndex + numValues); | ensureSize (startIndex + numValues); | ||||
| @@ -317,8 +326,29 @@ public: | |||||
| dest[i] = source[i]; | 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: | private: | ||||
| Array <MinMaxValue> data; | Array <MinMaxValue> data; | ||||
| int peakLevel; | |||||
| void ensureSize (const int thumbSamples) | void ensureSize (const int thumbSamples) | ||||
| { | { | ||||
| @@ -700,6 +730,16 @@ bool AudioThumbnail::isFullyLoaded() const throw() | |||||
| return numSamplesFinished >= totalSamples - samplesPerThumbSample; | 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, | void AudioThumbnail::drawChannel (Graphics& g, const Rectangle<int>& area, double startTime, | ||||
| double endTime, int channelNum, float verticalZoomFactor) | double endTime, int channelNum, float verticalZoomFactor) | ||||
| { | { | ||||
| @@ -177,6 +177,12 @@ public: | |||||
| /** Returns true if the low res preview is fully generated. */ | /** Returns true if the low res preview is fully generated. */ | ||||
| bool isFullyLoaded() const throw(); | 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(). */ | /** Returns the hash code that was set by setSource() or setReader(). */ | ||||
| int64 getHashCode() const; | int64 getHashCode() const; | ||||
| @@ -546,10 +546,10 @@ public: | |||||
| : graph (graph_), | : graph (graph_), | ||||
| orderedNodes (orderedNodes_) | orderedNodes (orderedNodes_) | ||||
| { | { | ||||
| nodeIds.add (zeroNodeID); // first buffer is read-only zeros | |||||
| nodeIds.add ((uint32) zeroNodeID); // first buffer is read-only zeros | |||||
| channels.add (0); | channels.add (0); | ||||
| midiNodeIds.add (zeroNodeID); | |||||
| midiNodeIds.add ((uint32) zeroNodeID); | |||||
| for (int i = 0; i < orderedNodes.size(); ++i) | for (int i = 0; i < orderedNodes.size(); ++i) | ||||
| { | { | ||||
| @@ -835,7 +835,7 @@ private: | |||||
| if (midiNodeIds.getUnchecked(i) == freeNodeID) | if (midiNodeIds.getUnchecked(i) == freeNodeID) | ||||
| return i; | return i; | ||||
| midiNodeIds.add (freeNodeID); | |||||
| midiNodeIds.add ((uint32) freeNodeID); | |||||
| return midiNodeIds.size() - 1; | return midiNodeIds.size() - 1; | ||||
| } | } | ||||
| else | else | ||||
| @@ -844,7 +844,7 @@ private: | |||||
| if (nodeIds.getUnchecked(i) == freeNodeID) | if (nodeIds.getUnchecked(i) == freeNodeID) | ||||
| return i; | return i; | ||||
| nodeIds.add (freeNodeID); | |||||
| nodeIds.add ((uint32) freeNodeID); | |||||
| channels.add (0); | channels.add (0); | ||||
| return nodeIds.size() - 1; | return nodeIds.size() - 1; | ||||
| } | } | ||||
| @@ -884,7 +884,7 @@ private: | |||||
| nodeIds.getUnchecked(i), | nodeIds.getUnchecked(i), | ||||
| channels.getUnchecked(i))) | channels.getUnchecked(i))) | ||||
| { | { | ||||
| nodeIds.set (i, freeNodeID); | |||||
| nodeIds.set (i, (uint32) freeNodeID); | |||||
| } | } | ||||
| } | } | ||||
| @@ -895,7 +895,7 @@ private: | |||||
| midiNodeIds.getUnchecked(i), | midiNodeIds.getUnchecked(i), | ||||
| AudioProcessorGraph::midiChannelIndex)) | AudioProcessorGraph::midiChannelIndex)) | ||||
| { | { | ||||
| midiNodeIds.set (i, freeNodeID); | |||||
| midiNodeIds.set (i, (uint32) freeNodeID); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -33,7 +33,7 @@ | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 52 | #define JUCE_MINOR_VERSION 52 | ||||
| #define JUCE_BUILDNUMBER 105 | |||||
| #define JUCE_BUILDNUMBER 106 | |||||
| /** Current Juce version number. | /** 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 | 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 | 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 | 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 | 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 | different frequencies, then the MultiTimer class allows you to do that - its | ||||
| @@ -470,8 +470,7 @@ void Component::setVisible (bool shouldBeVisible) | |||||
| if (! shouldBeVisible) | if (! shouldBeVisible) | ||||
| { | { | ||||
| if (currentlyFocusedComponent == this | |||||
| || isParentOf (currentlyFocusedComponent)) | |||||
| if (currentlyFocusedComponent == this || isParentOf (currentlyFocusedComponent)) | |||||
| { | { | ||||
| if (parentComponent_ != 0) | if (parentComponent_ != 0) | ||||
| parentComponent_->grabKeyboardFocus(); | parentComponent_->grabKeyboardFocus(); | ||||
| @@ -1358,32 +1357,18 @@ Component* Component::removeChildComponent (const int index) | |||||
| childComponentList_.remove (index); | childComponentList_.remove (index); | ||||
| child->parentComponent_ = 0; | 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(); | child->internalHierarchyChanged(); | ||||
| @@ -2854,14 +2839,13 @@ Component* JUCE_CALLTYPE Component::getCurrentlyFocusedComponent() throw() | |||||
| void Component::giveAwayFocus() | 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; | currentlyFocusedComponent = 0; | ||||
| Desktop::getInstance().triggerFocusCallback(); | |||||
| if (componentLosingFocus != 0) | if (componentLosingFocus != 0) | ||||
| componentLosingFocus->internalFocusLoss (focusChangedDirectly); | componentLosingFocus->internalFocusLoss (focusChangedDirectly); | ||||
| Desktop::getInstance().triggerFocusCallback(); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -2171,9 +2171,9 @@ private: | |||||
| bool isDisabledFlag : 1; | bool isDisabledFlag : 1; | ||||
| bool childCompFocusedFlag : 1; | bool childCompFocusedFlag : 1; | ||||
| bool dontClipGraphicsFlag : 1; | bool dontClipGraphicsFlag : 1; | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| bool isInsidePaintCall : 1; | bool isInsidePaintCall : 1; | ||||
| #endif | |||||
| #endif | |||||
| }; | }; | ||||
| union | union | ||||