| @@ -12214,6 +12214,10 @@ const char* String::toUTF8() const | |||
| mutableThis->text = StringHolder::makeUniqueWithSize (mutableThis->text, currentLen + 1 + utf8BytesNeeded / sizeof (juce_wchar)); | |||
| char* const otherCopy = reinterpret_cast <char*> (mutableThis->text + currentLen); | |||
| #if JUCE_DEBUG // (This just avoids spurious warnings from valgrind about the uninitialised bytes at the end of the buffer..) | |||
| *(juce_wchar*) (otherCopy + (utf8BytesNeeded & ~(sizeof (juce_wchar) - 1))) = 0; | |||
| #endif | |||
| copyToUTF8 (otherCopy, std::numeric_limits<int>::max()); | |||
| return otherCopy; | |||
| @@ -23702,13 +23706,15 @@ END_JUCE_NAMESPACE | |||
| BEGIN_JUCE_NAMESPACE | |||
| ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource, | |||
| const bool deleteInputWhenDeleted_) | |||
| const bool deleteInputWhenDeleted_, | |||
| const int numChannels_) | |||
| : input (inputSource), | |||
| deleteInputWhenDeleted (deleteInputWhenDeleted_), | |||
| ratio (1.0), | |||
| lastRatio (1.0), | |||
| buffer (2, 0), | |||
| sampsInBuffer (0) | |||
| buffer (numChannels_, 0), | |||
| sampsInBuffer (0), | |||
| numChannels (numChannels_) | |||
| { | |||
| jassert (input != 0); | |||
| } | |||
| @@ -23734,12 +23740,15 @@ void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, | |||
| input->prepareToPlay (samplesPerBlockExpected, sampleRate); | |||
| buffer.setSize (2, roundToInt (samplesPerBlockExpected * ratio) + 32); | |||
| buffer.setSize (numChannels, roundToInt (samplesPerBlockExpected * ratio) + 32); | |||
| buffer.clear(); | |||
| sampsInBuffer = 0; | |||
| bufferPos = 0; | |||
| subSampleOffset = 0.0; | |||
| filterStates.calloc (numChannels); | |||
| srcBuffers.calloc (numChannels); | |||
| destBuffers.calloc (numChannels); | |||
| createLowPass (ratio); | |||
| resetFilters(); | |||
| } | |||
| @@ -23747,7 +23756,7 @@ void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, | |||
| void ResamplingAudioSource::releaseResources() | |||
| { | |||
| input->releaseResources(); | |||
| buffer.setSize (2, 0); | |||
| buffer.setSize (numChannels, 0); | |||
| } | |||
| void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) | |||
| @@ -23793,7 +23802,7 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf | |||
| { | |||
| // for down-sampling, pre-apply the filter.. | |||
| for (int i = jmin (2, info.buffer->getNumChannels()); --i >= 0;) | |||
| for (int i = jmin (numChannels, info.buffer->getNumChannels()); --i >= 0;) | |||
| applyFilter (buffer.getSampleData (i, endOfBufferPos), numToDo, filterStates[i]); | |||
| } | |||
| @@ -23801,23 +23810,20 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf | |||
| endOfBufferPos += numToDo; | |||
| } | |||
| float* dl = info.buffer->getSampleData (0, info.startSample); | |||
| float* dr = (info.buffer->getNumChannels() > 1) ? info.buffer->getSampleData (1, info.startSample) : 0; | |||
| const float* const bl = buffer.getSampleData (0, 0); | |||
| const float* const br = buffer.getSampleData (1, 0); | |||
| for (int channel = 0; channel < numChannels; ++channel) | |||
| { | |||
| destBuffers[channel] = info.buffer->getSampleData (channel, info.startSample); | |||
| srcBuffers[channel] = buffer.getSampleData (channel, 0); | |||
| } | |||
| int nextPos = (bufferPos + 1) % bufferSize; | |||
| for (int m = info.numSamples; --m >= 0;) | |||
| { | |||
| const float alpha = (float) subSampleOffset; | |||
| const float invAlpha = 1.0f - alpha; | |||
| *dl++ = bl [bufferPos] * invAlpha + bl [nextPos] * alpha; | |||
| if (dr != 0) | |||
| *dr++ = br [bufferPos] * invAlpha + br [nextPos] * alpha; | |||
| for (int channel = 0; channel < numChannels; ++channel) | |||
| *destBuffers[channel]++ = srcBuffers[channel][bufferPos] * invAlpha + srcBuffers[channel][nextPos] * alpha; | |||
| subSampleOffset += ratio; | |||
| @@ -23838,14 +23844,13 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf | |||
| if (ratio < 0.9999) | |||
| { | |||
| // for up-sampling, apply the filter after transposing.. | |||
| for (int i = jmin (2, info.buffer->getNumChannels()); --i >= 0;) | |||
| for (int i = jmin (numChannels, info.buffer->getNumChannels()); --i >= 0;) | |||
| applyFilter (info.buffer->getSampleData (i, info.startSample), info.numSamples, filterStates[i]); | |||
| } | |||
| else if (ratio <= 1.0001) | |||
| { | |||
| // if the filter's not currently being applied, keep it stoked with the last couple of samples to avoid discontinuities | |||
| for (int i = jmin (2, info.buffer->getNumChannels()); --i >= 0;) | |||
| for (int i = jmin (numChannels, info.buffer->getNumChannels()); --i >= 0;) | |||
| { | |||
| const float* const endOfBuffer = info.buffer->getSampleData (i, info.startSample + info.numSamples - 1); | |||
| FilterState& fs = filterStates[i]; | |||
| @@ -23904,7 +23909,7 @@ void ResamplingAudioSource::setFilterCoefficients (double c1, double c2, double | |||
| void ResamplingAudioSource::resetFilters() | |||
| { | |||
| zeromem (filterStates, sizeof (filterStates)); | |||
| zeromem (filterStates, sizeof (FilterState) * numChannels); | |||
| } | |||
| void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs) | |||
| @@ -26166,7 +26171,7 @@ void AudioSampleBuffer::readFromAudioReader (AudioFormatReader* reader, | |||
| const int numSamples, | |||
| const int readerStartSample, | |||
| const bool useLeftChan, | |||
| const bool useRightChan) throw() | |||
| const bool useRightChan) | |||
| { | |||
| jassert (reader != 0); | |||
| jassert (startSample >= 0 && startSample + numSamples <= size); | |||
| @@ -26223,62 +26228,46 @@ void AudioSampleBuffer::readFromAudioReader (AudioFormatReader* reader, | |||
| void AudioSampleBuffer::writeToAudioWriter (AudioFormatWriter* writer, | |||
| const int startSample, | |||
| const int numSamples) const throw() | |||
| const int numSamples) const | |||
| { | |||
| jassert (startSample >= 0 && startSample + numSamples <= size); | |||
| jassert (startSample >= 0 && startSample + numSamples <= size && numChannels > 0); | |||
| if (numSamples > 0) | |||
| { | |||
| int* chans [3]; | |||
| HeapBlock<int> tempBuffer; | |||
| HeapBlock<int*> chans (numChannels + 1); | |||
| chans [numChannels] = 0; | |||
| if (writer->isFloatingPoint()) | |||
| { | |||
| chans[0] = (int*) getSampleData (0, startSample); | |||
| if (numChannels > 1) | |||
| chans[1] = (int*) getSampleData (1, startSample); | |||
| else | |||
| chans[1] = 0; | |||
| chans[2] = 0; | |||
| writer->write ((const int**) chans, numSamples); | |||
| for (int i = numChannels; --i >= 0;) | |||
| chans[i] = (int*) channels[i] + startSample; | |||
| } | |||
| else | |||
| { | |||
| HeapBlock <int> tempBuffer (numSamples * 2); | |||
| chans[0] = tempBuffer; | |||
| if (numChannels > 1) | |||
| chans[1] = chans[0] + numSamples; | |||
| else | |||
| chans[1] = 0; | |||
| chans[2] = 0; | |||
| tempBuffer.malloc (numSamples * numChannels); | |||
| for (int j = 0; j < 2; ++j) | |||
| for (int j = 0; j < numChannels; ++j) | |||
| { | |||
| int* const dest = chans[j]; | |||
| int* const dest = tempBuffer + j * numSamples; | |||
| const float* const src = channels[j] + startSample; | |||
| chans[j] = dest; | |||
| if (dest != 0) | |||
| for (int i = 0; i < numSamples; ++i) | |||
| { | |||
| const float* const src = channels [j] + startSample; | |||
| for (int i = 0; i < numSamples; ++i) | |||
| { | |||
| const double samp = src[i]; | |||
| const double samp = src[i]; | |||
| if (samp <= -1.0) | |||
| dest[i] = std::numeric_limits<int>::min(); | |||
| else if (samp >= 1.0) | |||
| dest[i] = std::numeric_limits<int>::max(); | |||
| else | |||
| dest[i] = roundToInt (std::numeric_limits<int>::max() * samp); | |||
| } | |||
| if (samp <= -1.0) | |||
| dest[i] = std::numeric_limits<int>::min(); | |||
| else if (samp >= 1.0) | |||
| dest[i] = std::numeric_limits<int>::max(); | |||
| else | |||
| dest[i] = roundToInt (std::numeric_limits<int>::max() * samp); | |||
| } | |||
| } | |||
| writer->write ((const int**) chans, numSamples); | |||
| } | |||
| writer->write ((const int**) chans.getData(), numSamples); | |||
| } | |||
| } | |||
| @@ -29683,6 +29672,7 @@ PluginListComponent::PluginListComponent (KnownPluginList& listToEdit, | |||
| setSize (400, 600); | |||
| list.addChangeListener (this); | |||
| changeListenerCallback (0); | |||
| } | |||
| PluginListComponent::~PluginListComponent() | |||
| @@ -50950,14 +50940,6 @@ public: | |||
| return String::empty; | |||
| } | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| TableListBox& owner; | |||
| int row; | |||
| bool isSelected, isDragging, selectRowOnMouseUp; | |||
| BigInteger columnsWithComponents; | |||
| Component* findChildComponentForColumn (const int columnId) const | |||
| { | |||
| for (int i = getNumChildComponents(); --i >= 0;) | |||
| @@ -50971,6 +50953,14 @@ private: | |||
| return 0; | |||
| } | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| TableListBox& owner; | |||
| int row; | |||
| bool isSelected, isDragging, selectRowOnMouseUp; | |||
| BigInteger columnsWithComponents; | |||
| TableListRowComp (const TableListRowComp&); | |||
| TableListRowComp& operator= (const TableListRowComp&); | |||
| }; | |||
| @@ -51102,6 +51092,12 @@ const Rectangle<int> TableListBox::getCellPosition (const int columnId, | |||
| headerCell.getWidth(), row.getHeight()); | |||
| } | |||
| Component* TableListBox::getCellComponent (int columnId, int rowNumber) const | |||
| { | |||
| TableListRowComp* const rowComp = dynamic_cast <TableListRowComp*> (getComponentForRowNumber (rowNumber)); | |||
| return rowComp != 0 ? rowComp->findChildComponentForColumn (columnId) : 0; | |||
| } | |||
| void TableListBox::scrollToEnsureColumnIsOnscreen (const int columnId) | |||
| { | |||
| ScrollBar* const scrollbar = getHorizontalScrollBar(); | |||
| @@ -85775,10 +85771,10 @@ static const Point<float> findQuadraticSubdivisionPoint (double proportion, cons | |||
| return mid1 + (mid2 - mid1) * proportion; | |||
| } | |||
| ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager) | |||
| double DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder) const | |||
| { | |||
| ValueTree newTree; | |||
| const Identifier i (state.getType()); | |||
| double bestProp = 0; | |||
| if (i == cubicToElement) | |||
| { | |||
| @@ -85786,7 +85782,6 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<floa | |||
| const Point<float> points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder), rp4.resolve (nameFinder) }; | |||
| double bestProp = 0; | |||
| float bestDistance = std::numeric_limits<float>::max(); | |||
| for (int i = 110; --i >= 0;) | |||
| @@ -85801,6 +85796,48 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<floa | |||
| bestDistance = distance; | |||
| } | |||
| } | |||
| } | |||
| else if (i == quadraticToElement) | |||
| { | |||
| RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getEndPoint()); | |||
| const Point<float> points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder) }; | |||
| float bestDistance = std::numeric_limits<float>::max(); | |||
| for (int i = 110; --i >= 0;) | |||
| { | |||
| double prop = i > 10 ? ((i - 10) / 100.0) : (bestProp + ((i - 5) / 1000.0)); | |||
| const Point<float> centre (findQuadraticSubdivisionPoint (prop, points)); | |||
| const float distance = centre.getDistanceFrom (targetPoint); | |||
| if (distance < bestDistance) | |||
| { | |||
| bestProp = prop; | |||
| bestDistance = distance; | |||
| } | |||
| } | |||
| } | |||
| else if (i == lineToElement) | |||
| { | |||
| RelativePoint rp1 (getStartPoint()), rp2 (getEndPoint()); | |||
| const Line<float> line (rp1.resolve (nameFinder), rp2.resolve (nameFinder)); | |||
| bestProp = line.findNearestProportionalPositionTo (targetPoint); | |||
| } | |||
| return bestProp; | |||
| } | |||
| ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager) | |||
| { | |||
| ValueTree newTree; | |||
| const Identifier i (state.getType()); | |||
| if (i == cubicToElement) | |||
| { | |||
| double bestProp = findProportionAlongLine (targetPoint, nameFinder); | |||
| RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getControlPoint (1)), rp4 (getEndPoint()); | |||
| const Point<float> points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder), rp4.resolve (nameFinder) }; | |||
| const Point<float> mid1 (points[0] + (points[1] - points[0]) * bestProp), | |||
| mid2 (points[1] + (points[2] - points[1]) * bestProp), | |||
| @@ -85825,26 +85862,11 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<floa | |||
| } | |||
| else if (i == quadraticToElement) | |||
| { | |||
| RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getEndPoint()); | |||
| double bestProp = findProportionAlongLine (targetPoint, nameFinder); | |||
| RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getEndPoint()); | |||
| const Point<float> points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder) }; | |||
| double bestProp = 0; | |||
| float bestDistance = std::numeric_limits<float>::max(); | |||
| for (int i = 110; --i >= 0;) | |||
| { | |||
| double prop = i > 10 ? ((i - 10) / 100.0) : (bestProp + ((i - 5) / 1000.0)); | |||
| const Point<float> centre (findQuadraticSubdivisionPoint (prop, points)); | |||
| const float distance = centre.getDistanceFrom (targetPoint); | |||
| if (distance < bestDistance) | |||
| { | |||
| bestProp = prop; | |||
| bestDistance = distance; | |||
| } | |||
| } | |||
| const Point<float> mid1 (points[0] + (points[1] - points[0]) * bestProp), | |||
| mid2 (points[1] + (points[2] - points[1]) * bestProp); | |||
| @@ -64,7 +64,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 52 | |||
| #define JUCE_BUILDNUMBER 30 | |||
| #define JUCE_BUILDNUMBER 31 | |||
| /** Current Juce version number. | |||
| @@ -29669,7 +29669,7 @@ public: | |||
| int numSamples, | |||
| int readerStartSample, | |||
| bool useReaderLeftChan, | |||
| bool useReaderRightChan) throw(); | |||
| bool useReaderRightChan); | |||
| /** Writes a section of this buffer to an audio writer. | |||
| @@ -29680,7 +29680,7 @@ public: | |||
| */ | |||
| void writeToAudioWriter (AudioFormatWriter* writer, | |||
| int startSample, | |||
| int numSamples) const throw(); | |||
| int numSamples) const; | |||
| juce_UseDebuggingNewOperator | |||
| @@ -31739,9 +31739,11 @@ public: | |||
| @param inputSource the input source to read from | |||
| @param deleteInputWhenDeleted if true, the input source will be deleted when | |||
| this object is deleted | |||
| @param numChannels the number of channels to process | |||
| */ | |||
| ResamplingAudioSource (AudioSource* const inputSource, | |||
| const bool deleteInputWhenDeleted); | |||
| const bool deleteInputWhenDeleted, | |||
| int numChannels = 2); | |||
| /** Destructor. */ | |||
| ~ResamplingAudioSource(); | |||
| @@ -31777,6 +31779,8 @@ private: | |||
| double subSampleOffset; | |||
| double coefficients[6]; | |||
| CriticalSection ratioLock; | |||
| const int numChannels; | |||
| HeapBlock<float*> destBuffers, srcBuffers; | |||
| void setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6); | |||
| void createLowPass (const double proportionalRate); | |||
| @@ -31786,7 +31790,7 @@ private: | |||
| double x1, x2, y1, y2; | |||
| }; | |||
| FilterState filterStates[2]; | |||
| HeapBlock<FilterState> filterStates; | |||
| void resetFilters(); | |||
| void applyFilter (float* samples, int num, FilterState& fs); | |||
| @@ -36664,6 +36668,9 @@ public: | |||
| */ | |||
| void showEditor(); | |||
| /** Pops up the combo box's list. */ | |||
| void showPopup(); | |||
| /** Registers a listener that will be called when the box's content changes. */ | |||
| void addListener (ComboBoxListener* listener) throw(); | |||
| @@ -36773,8 +36780,6 @@ private: | |||
| ScopedPointer<Label> label; | |||
| String textWhenNothingSelected, noChoicesMessage; | |||
| void showPopup(); | |||
| ItemInfo* getItemForId (int itemId) const throw(); | |||
| ItemInfo* getItemForIndex (int index) const throw(); | |||
| @@ -47165,10 +47170,16 @@ public: | |||
| If relativeToComponentTopLeft is false, the co-ords are relative to the | |||
| top-left of the table's top-left cell. | |||
| */ | |||
| const Rectangle<int> getCellPosition (int columnId, | |||
| int rowNumber, | |||
| const Rectangle<int> getCellPosition (int columnId, int rowNumber, | |||
| bool relativeToComponentTopLeft) const; | |||
| /** Returns the component that currently represents a given cell. | |||
| If the component for this cell is off-screen or if the position is out-of-range, | |||
| this may return 0. | |||
| @see getCellPosition | |||
| */ | |||
| Component* getCellComponent (int columnId, int rowNumber) const; | |||
| /** Scrolls horizontally if necessary to make sure that a particular column is visible. | |||
| @see ListBox::scrollToEnsureRowIsOnscreen | |||
| @@ -59405,6 +59416,7 @@ public: | |||
| void convertToPathBreak (UndoManager* undoManager); | |||
| ValueTree insertPoint (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager); | |||
| void removePoint (UndoManager* undoManager); | |||
| double findProportionAlongLine (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder) const; | |||
| static const Identifier mode, startSubPathElement, closeSubPathElement, | |||
| lineToElement, quadraticToElement, cubicToElement; | |||
| @@ -33,13 +33,15 @@ BEGIN_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource, | |||
| const bool deleteInputWhenDeleted_) | |||
| const bool deleteInputWhenDeleted_, | |||
| const int numChannels_) | |||
| : input (inputSource), | |||
| deleteInputWhenDeleted (deleteInputWhenDeleted_), | |||
| ratio (1.0), | |||
| lastRatio (1.0), | |||
| buffer (2, 0), | |||
| sampsInBuffer (0) | |||
| buffer (numChannels_, 0), | |||
| sampsInBuffer (0), | |||
| numChannels (numChannels_) | |||
| { | |||
| jassert (input != 0); | |||
| } | |||
| @@ -65,12 +67,15 @@ void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, | |||
| input->prepareToPlay (samplesPerBlockExpected, sampleRate); | |||
| buffer.setSize (2, roundToInt (samplesPerBlockExpected * ratio) + 32); | |||
| buffer.setSize (numChannels, roundToInt (samplesPerBlockExpected * ratio) + 32); | |||
| buffer.clear(); | |||
| sampsInBuffer = 0; | |||
| bufferPos = 0; | |||
| subSampleOffset = 0.0; | |||
| filterStates.calloc (numChannels); | |||
| srcBuffers.calloc (numChannels); | |||
| destBuffers.calloc (numChannels); | |||
| createLowPass (ratio); | |||
| resetFilters(); | |||
| } | |||
| @@ -78,7 +83,7 @@ void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, | |||
| void ResamplingAudioSource::releaseResources() | |||
| { | |||
| input->releaseResources(); | |||
| buffer.setSize (2, 0); | |||
| buffer.setSize (numChannels, 0); | |||
| } | |||
| void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) | |||
| @@ -124,7 +129,7 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf | |||
| { | |||
| // for down-sampling, pre-apply the filter.. | |||
| for (int i = jmin (2, info.buffer->getNumChannels()); --i >= 0;) | |||
| for (int i = jmin (numChannels, info.buffer->getNumChannels()); --i >= 0;) | |||
| applyFilter (buffer.getSampleData (i, endOfBufferPos), numToDo, filterStates[i]); | |||
| } | |||
| @@ -132,23 +137,20 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf | |||
| endOfBufferPos += numToDo; | |||
| } | |||
| float* dl = info.buffer->getSampleData (0, info.startSample); | |||
| float* dr = (info.buffer->getNumChannels() > 1) ? info.buffer->getSampleData (1, info.startSample) : 0; | |||
| const float* const bl = buffer.getSampleData (0, 0); | |||
| const float* const br = buffer.getSampleData (1, 0); | |||
| for (int channel = 0; channel < numChannels; ++channel) | |||
| { | |||
| destBuffers[channel] = info.buffer->getSampleData (channel, info.startSample); | |||
| srcBuffers[channel] = buffer.getSampleData (channel, 0); | |||
| } | |||
| int nextPos = (bufferPos + 1) % bufferSize; | |||
| for (int m = info.numSamples; --m >= 0;) | |||
| { | |||
| const float alpha = (float) subSampleOffset; | |||
| const float invAlpha = 1.0f - alpha; | |||
| *dl++ = bl [bufferPos] * invAlpha + bl [nextPos] * alpha; | |||
| if (dr != 0) | |||
| *dr++ = br [bufferPos] * invAlpha + br [nextPos] * alpha; | |||
| for (int channel = 0; channel < numChannels; ++channel) | |||
| *destBuffers[channel]++ = srcBuffers[channel][bufferPos] * invAlpha + srcBuffers[channel][nextPos] * alpha; | |||
| subSampleOffset += ratio; | |||
| @@ -169,14 +171,13 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf | |||
| if (ratio < 0.9999) | |||
| { | |||
| // for up-sampling, apply the filter after transposing.. | |||
| for (int i = jmin (2, info.buffer->getNumChannels()); --i >= 0;) | |||
| for (int i = jmin (numChannels, info.buffer->getNumChannels()); --i >= 0;) | |||
| applyFilter (info.buffer->getSampleData (i, info.startSample), info.numSamples, filterStates[i]); | |||
| } | |||
| else if (ratio <= 1.0001) | |||
| { | |||
| // if the filter's not currently being applied, keep it stoked with the last couple of samples to avoid discontinuities | |||
| for (int i = jmin (2, info.buffer->getNumChannels()); --i >= 0;) | |||
| for (int i = jmin (numChannels, info.buffer->getNumChannels()); --i >= 0;) | |||
| { | |||
| const float* const endOfBuffer = info.buffer->getSampleData (i, info.startSample + info.numSamples - 1); | |||
| FilterState& fs = filterStates[i]; | |||
| @@ -235,7 +236,7 @@ void ResamplingAudioSource::setFilterCoefficients (double c1, double c2, double | |||
| void ResamplingAudioSource::resetFilters() | |||
| { | |||
| zeromem (filterStates, sizeof (filterStates)); | |||
| zeromem (filterStates, sizeof (FilterState) * numChannels); | |||
| } | |||
| void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs) | |||
| @@ -29,6 +29,7 @@ | |||
| #include "juce_AudioSource.h" | |||
| #include "../../threads/juce_CriticalSection.h" | |||
| //============================================================================== | |||
| /** | |||
| A type of AudioSource that takes an input source and changes its sample rate. | |||
| @@ -44,9 +45,11 @@ public: | |||
| @param inputSource the input source to read from | |||
| @param deleteInputWhenDeleted if true, the input source will be deleted when | |||
| this object is deleted | |||
| @param numChannels the number of channels to process | |||
| */ | |||
| ResamplingAudioSource (AudioSource* const inputSource, | |||
| const bool deleteInputWhenDeleted); | |||
| const bool deleteInputWhenDeleted, | |||
| int numChannels = 2); | |||
| /** Destructor. */ | |||
| ~ResamplingAudioSource(); | |||
| @@ -84,6 +87,8 @@ private: | |||
| double subSampleOffset; | |||
| double coefficients[6]; | |||
| CriticalSection ratioLock; | |||
| const int numChannels; | |||
| HeapBlock<float*> destBuffers, srcBuffers; | |||
| void setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6); | |||
| void createLowPass (const double proportionalRate); | |||
| @@ -93,7 +98,7 @@ private: | |||
| double x1, x2, y1, y2; | |||
| }; | |||
| FilterState filterStates[2]; | |||
| HeapBlock<FilterState> filterStates; | |||
| void resetFilters(); | |||
| void applyFilter (float* samples, int num, FilterState& fs); | |||
| @@ -574,7 +574,7 @@ void AudioSampleBuffer::readFromAudioReader (AudioFormatReader* reader, | |||
| const int numSamples, | |||
| const int readerStartSample, | |||
| const bool useLeftChan, | |||
| const bool useRightChan) throw() | |||
| const bool useRightChan) | |||
| { | |||
| jassert (reader != 0); | |||
| jassert (startSample >= 0 && startSample + numSamples <= size); | |||
| @@ -631,62 +631,46 @@ void AudioSampleBuffer::readFromAudioReader (AudioFormatReader* reader, | |||
| void AudioSampleBuffer::writeToAudioWriter (AudioFormatWriter* writer, | |||
| const int startSample, | |||
| const int numSamples) const throw() | |||
| const int numSamples) const | |||
| { | |||
| jassert (startSample >= 0 && startSample + numSamples <= size); | |||
| jassert (startSample >= 0 && startSample + numSamples <= size && numChannels > 0); | |||
| if (numSamples > 0) | |||
| { | |||
| int* chans [3]; | |||
| HeapBlock<int> tempBuffer; | |||
| HeapBlock<int*> chans (numChannels + 1); | |||
| chans [numChannels] = 0; | |||
| if (writer->isFloatingPoint()) | |||
| { | |||
| chans[0] = (int*) getSampleData (0, startSample); | |||
| if (numChannels > 1) | |||
| chans[1] = (int*) getSampleData (1, startSample); | |||
| else | |||
| chans[1] = 0; | |||
| chans[2] = 0; | |||
| writer->write ((const int**) chans, numSamples); | |||
| for (int i = numChannels; --i >= 0;) | |||
| chans[i] = (int*) channels[i] + startSample; | |||
| } | |||
| else | |||
| { | |||
| HeapBlock <int> tempBuffer (numSamples * 2); | |||
| chans[0] = tempBuffer; | |||
| if (numChannels > 1) | |||
| chans[1] = chans[0] + numSamples; | |||
| else | |||
| chans[1] = 0; | |||
| tempBuffer.malloc (numSamples * numChannels); | |||
| chans[2] = 0; | |||
| for (int j = 0; j < 2; ++j) | |||
| for (int j = 0; j < numChannels; ++j) | |||
| { | |||
| int* const dest = chans[j]; | |||
| int* const dest = tempBuffer + j * numSamples; | |||
| const float* const src = channels[j] + startSample; | |||
| chans[j] = dest; | |||
| if (dest != 0) | |||
| for (int i = 0; i < numSamples; ++i) | |||
| { | |||
| const float* const src = channels [j] + startSample; | |||
| for (int i = 0; i < numSamples; ++i) | |||
| { | |||
| const double samp = src[i]; | |||
| if (samp <= -1.0) | |||
| dest[i] = std::numeric_limits<int>::min(); | |||
| else if (samp >= 1.0) | |||
| dest[i] = std::numeric_limits<int>::max(); | |||
| else | |||
| dest[i] = roundToInt (std::numeric_limits<int>::max() * samp); | |||
| } | |||
| const double samp = src[i]; | |||
| if (samp <= -1.0) | |||
| dest[i] = std::numeric_limits<int>::min(); | |||
| else if (samp >= 1.0) | |||
| dest[i] = std::numeric_limits<int>::max(); | |||
| else | |||
| dest[i] = roundToInt (std::numeric_limits<int>::max() * samp); | |||
| } | |||
| } | |||
| writer->write ((const int**) chans, numSamples); | |||
| } | |||
| writer->write ((const int**) chans.getData(), numSamples); | |||
| } | |||
| } | |||
| @@ -407,7 +407,7 @@ public: | |||
| int numSamples, | |||
| int readerStartSample, | |||
| bool useReaderLeftChan, | |||
| bool useReaderRightChan) throw(); | |||
| bool useReaderRightChan); | |||
| /** Writes a section of this buffer to an audio writer. | |||
| @@ -418,7 +418,7 @@ public: | |||
| */ | |||
| void writeToAudioWriter (AudioFormatWriter* writer, | |||
| int startSample, | |||
| int numSamples) const throw(); | |||
| int numSamples) const; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| @@ -53,6 +53,7 @@ PluginListComponent::PluginListComponent (KnownPluginList& listToEdit, | |||
| setSize (400, 600); | |||
| list.addChangeListener (this); | |||
| changeListenerCallback (0); | |||
| } | |||
| PluginListComponent::~PluginListComponent() | |||
| @@ -33,7 +33,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 52 | |||
| #define JUCE_BUILDNUMBER 30 | |||
| #define JUCE_BUILDNUMBER 31 | |||
| /** Current Juce version number. | |||
| @@ -282,6 +282,9 @@ public: | |||
| */ | |||
| void showEditor(); | |||
| /** Pops up the combo box's list. */ | |||
| void showPopup(); | |||
| //============================================================================== | |||
| /** Registers a listener that will be called when the box's content changes. */ | |||
| void addListener (ComboBoxListener* listener) throw(); | |||
| @@ -399,8 +402,6 @@ private: | |||
| ScopedPointer<Label> label; | |||
| String textWhenNothingSelected, noChoicesMessage; | |||
| void showPopup(); | |||
| ItemInfo* getItemForId (int itemId) const throw(); | |||
| ItemInfo* getItemForIndex (int index) const throw(); | |||
| @@ -237,14 +237,6 @@ public: | |||
| return String::empty; | |||
| } | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| TableListBox& owner; | |||
| int row; | |||
| bool isSelected, isDragging, selectRowOnMouseUp; | |||
| BigInteger columnsWithComponents; | |||
| Component* findChildComponentForColumn (const int columnId) const | |||
| { | |||
| for (int i = getNumChildComponents(); --i >= 0;) | |||
| @@ -258,6 +250,14 @@ private: | |||
| return 0; | |||
| } | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| TableListBox& owner; | |||
| int row; | |||
| bool isSelected, isDragging, selectRowOnMouseUp; | |||
| BigInteger columnsWithComponents; | |||
| TableListRowComp (const TableListRowComp&); | |||
| TableListRowComp& operator= (const TableListRowComp&); | |||
| }; | |||
| @@ -392,6 +392,12 @@ const Rectangle<int> TableListBox::getCellPosition (const int columnId, | |||
| headerCell.getWidth(), row.getHeight()); | |||
| } | |||
| Component* TableListBox::getCellComponent (int columnId, int rowNumber) const | |||
| { | |||
| TableListRowComp* const rowComp = dynamic_cast <TableListRowComp*> (getComponentForRowNumber (rowNumber)); | |||
| return rowComp != 0 ? rowComp->findChildComponentForColumn (columnId) : 0; | |||
| } | |||
| void TableListBox::scrollToEnsureColumnIsOnscreen (const int columnId) | |||
| { | |||
| ScrollBar* const scrollbar = getHorizontalScrollBar(); | |||
| @@ -269,10 +269,16 @@ public: | |||
| If relativeToComponentTopLeft is false, the co-ords are relative to the | |||
| top-left of the table's top-left cell. | |||
| */ | |||
| const Rectangle<int> getCellPosition (int columnId, | |||
| int rowNumber, | |||
| const Rectangle<int> getCellPosition (int columnId, int rowNumber, | |||
| bool relativeToComponentTopLeft) const; | |||
| /** Returns the component that currently represents a given cell. | |||
| If the component for this cell is off-screen or if the position is out-of-range, | |||
| this may return 0. | |||
| @see getCellPosition | |||
| */ | |||
| Component* getCellComponent (int columnId, int rowNumber) const; | |||
| /** Scrolls horizontally if necessary to make sure that a particular column is visible. | |||
| @see ListBox::scrollToEnsureRowIsOnscreen | |||
| @@ -473,10 +473,10 @@ static const Point<float> findQuadraticSubdivisionPoint (double proportion, cons | |||
| return mid1 + (mid2 - mid1) * proportion; | |||
| } | |||
| ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager) | |||
| double DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder) const | |||
| { | |||
| ValueTree newTree; | |||
| const Identifier i (state.getType()); | |||
| double bestProp = 0; | |||
| if (i == cubicToElement) | |||
| { | |||
| @@ -484,7 +484,6 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<floa | |||
| const Point<float> points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder), rp4.resolve (nameFinder) }; | |||
| double bestProp = 0; | |||
| float bestDistance = std::numeric_limits<float>::max(); | |||
| for (int i = 110; --i >= 0;) | |||
| @@ -499,6 +498,48 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<floa | |||
| bestDistance = distance; | |||
| } | |||
| } | |||
| } | |||
| else if (i == quadraticToElement) | |||
| { | |||
| RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getEndPoint()); | |||
| const Point<float> points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder) }; | |||
| float bestDistance = std::numeric_limits<float>::max(); | |||
| for (int i = 110; --i >= 0;) | |||
| { | |||
| double prop = i > 10 ? ((i - 10) / 100.0) : (bestProp + ((i - 5) / 1000.0)); | |||
| const Point<float> centre (findQuadraticSubdivisionPoint (prop, points)); | |||
| const float distance = centre.getDistanceFrom (targetPoint); | |||
| if (distance < bestDistance) | |||
| { | |||
| bestProp = prop; | |||
| bestDistance = distance; | |||
| } | |||
| } | |||
| } | |||
| else if (i == lineToElement) | |||
| { | |||
| RelativePoint rp1 (getStartPoint()), rp2 (getEndPoint()); | |||
| const Line<float> line (rp1.resolve (nameFinder), rp2.resolve (nameFinder)); | |||
| bestProp = line.findNearestProportionalPositionTo (targetPoint); | |||
| } | |||
| return bestProp; | |||
| } | |||
| ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager) | |||
| { | |||
| ValueTree newTree; | |||
| const Identifier i (state.getType()); | |||
| if (i == cubicToElement) | |||
| { | |||
| double bestProp = findProportionAlongLine (targetPoint, nameFinder); | |||
| RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getControlPoint (1)), rp4 (getEndPoint()); | |||
| const Point<float> points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder), rp4.resolve (nameFinder) }; | |||
| const Point<float> mid1 (points[0] + (points[1] - points[0]) * bestProp), | |||
| mid2 (points[1] + (points[2] - points[1]) * bestProp), | |||
| @@ -523,26 +564,11 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<floa | |||
| } | |||
| else if (i == quadraticToElement) | |||
| { | |||
| RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getEndPoint()); | |||
| double bestProp = findProportionAlongLine (targetPoint, nameFinder); | |||
| RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getEndPoint()); | |||
| const Point<float> points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder) }; | |||
| double bestProp = 0; | |||
| float bestDistance = std::numeric_limits<float>::max(); | |||
| for (int i = 110; --i >= 0;) | |||
| { | |||
| double prop = i > 10 ? ((i - 10) / 100.0) : (bestProp + ((i - 5) / 1000.0)); | |||
| const Point<float> centre (findQuadraticSubdivisionPoint (prop, points)); | |||
| const float distance = centre.getDistanceFrom (targetPoint); | |||
| if (distance < bestDistance) | |||
| { | |||
| bestProp = prop; | |||
| bestDistance = distance; | |||
| } | |||
| } | |||
| const Point<float> mid1 (points[0] + (points[1] - points[0]) * bestProp), | |||
| mid2 (points[1] + (points[2] - points[1]) * bestProp); | |||
| @@ -176,6 +176,7 @@ public: | |||
| void convertToPathBreak (UndoManager* undoManager); | |||
| ValueTree insertPoint (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager); | |||
| void removePoint (UndoManager* undoManager); | |||
| double findProportionAlongLine (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder) const; | |||
| static const Identifier mode, startSubPathElement, closeSubPathElement, | |||
| lineToElement, quadraticToElement, cubicToElement; | |||
| @@ -1928,6 +1928,10 @@ const char* String::toUTF8() const | |||
| mutableThis->text = StringHolder::makeUniqueWithSize (mutableThis->text, currentLen + 1 + utf8BytesNeeded / sizeof (juce_wchar)); | |||
| char* const otherCopy = reinterpret_cast <char*> (mutableThis->text + currentLen); | |||
| #if JUCE_DEBUG // (This just avoids spurious warnings from valgrind about the uninitialised bytes at the end of the buffer..) | |||
| *(juce_wchar*) (otherCopy + (utf8BytesNeeded & ~(sizeof (juce_wchar) - 1))) = 0; | |||
| #endif | |||
| copyToUTF8 (otherCopy, std::numeric_limits<int>::max()); | |||
| return otherCopy; | |||