From e502d753d77d27459d402c462478e2de347d857e Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Wed, 30 Jun 2010 09:25:40 +0100 Subject: [PATCH] New method for TableListBox and ComboBox, made AudioSampleBuffer::writeToAudioWriter and ResamplingAudioSource handle multiple channels. --- juce_amalgamated.cpp | 196 ++++++++++-------- juce_amalgamated.h | 30 ++- .../juce_ResamplingAudioSource.cpp | 41 ++-- .../juce_ResamplingAudioSource.h | 9 +- src/audio/dsp/juce_AudioSampleBuffer.cpp | 64 +++--- src/audio/dsp/juce_AudioSampleBuffer.h | 4 +- .../plugins/juce_PluginListComponent.cpp | 1 + src/core/juce_StandardHeader.h | 2 +- src/gui/components/controls/juce_ComboBox.h | 5 +- .../components/controls/juce_TableListBox.cpp | 22 +- .../components/controls/juce_TableListBox.h | 10 +- .../graphics/drawables/juce_DrawablePath.cpp | 66 ++++-- .../graphics/drawables/juce_DrawablePath.h | 1 + src/text/juce_String.cpp | 4 + 14 files changed, 262 insertions(+), 193 deletions(-) diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 176cb63084..e8c586f8d6 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -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 (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::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 tempBuffer; + HeapBlock 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 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::min(); - else if (samp >= 1.0) - dest[i] = std::numeric_limits::max(); - else - dest[i] = roundToInt (std::numeric_limits::max() * samp); - } + if (samp <= -1.0) + dest[i] = std::numeric_limits::min(); + else if (samp >= 1.0) + dest[i] = std::numeric_limits::max(); + else + dest[i] = roundToInt (std::numeric_limits::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 TableListBox::getCellPosition (const int columnId, headerCell.getWidth(), row.getHeight()); } +Component* TableListBox::getCellComponent (int columnId, int rowNumber) const +{ + TableListRowComp* const rowComp = dynamic_cast (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 findQuadraticSubdivisionPoint (double proportion, cons return mid1 + (mid2 - mid1) * proportion; } -ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager) +double DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point& 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 points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder), rp4.resolve (nameFinder) }; - double bestProp = 0; float bestDistance = std::numeric_limits::max(); for (int i = 110; --i >= 0;) @@ -85801,6 +85796,48 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder) }; + + float bestDistance = std::numeric_limits::max(); + + for (int i = 110; --i >= 0;) + { + double prop = i > 10 ? ((i - 10) / 100.0) : (bestProp + ((i - 5) / 1000.0)); + const Point 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 line (rp1.resolve (nameFinder), rp2.resolve (nameFinder)); + bestProp = line.findNearestProportionalPositionTo (targetPoint); + } + + return bestProp; +} + +ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point& 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 points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder), rp4.resolve (nameFinder) }; const Point 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 points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder) }; - double bestProp = 0; - float bestDistance = std::numeric_limits::max(); - - for (int i = 110; --i >= 0;) - { - double prop = i > 10 ? ((i - 10) / 100.0) : (bestProp + ((i - 5) / 1000.0)); - const Point centre (findQuadraticSubdivisionPoint (prop, points)); - const float distance = centre.getDistanceFrom (targetPoint); - - if (distance < bestDistance) - { - bestProp = prop; - bestDistance = distance; - } - } - const Point mid1 (points[0] + (points[1] - points[0]) * bestProp), mid2 (points[1] + (points[2] - points[1]) * bestProp); diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 250e83e90b..1d8358b031 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -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 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 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