Browse Source

New method for TableListBox and ComboBox, made AudioSampleBuffer::writeToAudioWriter and ResamplingAudioSource handle multiple channels.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
e502d753d7
14 changed files with 262 additions and 193 deletions
  1. +109
    -87
      juce_amalgamated.cpp
  2. +21
    -9
      juce_amalgamated.h
  3. +21
    -20
      src/audio/audio_sources/juce_ResamplingAudioSource.cpp
  4. +7
    -2
      src/audio/audio_sources/juce_ResamplingAudioSource.h
  5. +24
    -40
      src/audio/dsp/juce_AudioSampleBuffer.cpp
  6. +2
    -2
      src/audio/dsp/juce_AudioSampleBuffer.h
  7. +1
    -0
      src/audio/plugins/juce_PluginListComponent.cpp
  8. +1
    -1
      src/core/juce_StandardHeader.h
  9. +3
    -2
      src/gui/components/controls/juce_ComboBox.h
  10. +14
    -8
      src/gui/components/controls/juce_TableListBox.cpp
  11. +8
    -2
      src/gui/components/controls/juce_TableListBox.h
  12. +46
    -20
      src/gui/graphics/drawables/juce_DrawablePath.cpp
  13. +1
    -0
      src/gui/graphics/drawables/juce_DrawablePath.h
  14. +4
    -0
      src/text/juce_String.cpp

+ 109
- 87
juce_amalgamated.cpp View File

@@ -12214,6 +12214,10 @@ const char* String::toUTF8() const
mutableThis->text = StringHolder::makeUniqueWithSize (mutableThis->text, currentLen + 1 + utf8BytesNeeded / sizeof (juce_wchar)); mutableThis->text = StringHolder::makeUniqueWithSize (mutableThis->text, currentLen + 1 + utf8BytesNeeded / sizeof (juce_wchar));


char* const otherCopy = reinterpret_cast <char*> (mutableThis->text + currentLen); 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()); copyToUTF8 (otherCopy, std::numeric_limits<int>::max());


return otherCopy; return otherCopy;
@@ -23702,13 +23706,15 @@ END_JUCE_NAMESPACE
BEGIN_JUCE_NAMESPACE BEGIN_JUCE_NAMESPACE


ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource, ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource,
const bool deleteInputWhenDeleted_)
const bool deleteInputWhenDeleted_,
const int numChannels_)
: input (inputSource), : input (inputSource),
deleteInputWhenDeleted (deleteInputWhenDeleted_), deleteInputWhenDeleted (deleteInputWhenDeleted_),
ratio (1.0), ratio (1.0),
lastRatio (1.0), lastRatio (1.0),
buffer (2, 0),
sampsInBuffer (0)
buffer (numChannels_, 0),
sampsInBuffer (0),
numChannels (numChannels_)
{ {
jassert (input != 0); jassert (input != 0);
} }
@@ -23734,12 +23740,15 @@ void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected,


input->prepareToPlay (samplesPerBlockExpected, sampleRate); input->prepareToPlay (samplesPerBlockExpected, sampleRate);


buffer.setSize (2, roundToInt (samplesPerBlockExpected * ratio) + 32);
buffer.setSize (numChannels, roundToInt (samplesPerBlockExpected * ratio) + 32);
buffer.clear(); buffer.clear();
sampsInBuffer = 0; sampsInBuffer = 0;
bufferPos = 0; bufferPos = 0;
subSampleOffset = 0.0; subSampleOffset = 0.0;


filterStates.calloc (numChannels);
srcBuffers.calloc (numChannels);
destBuffers.calloc (numChannels);
createLowPass (ratio); createLowPass (ratio);
resetFilters(); resetFilters();
} }
@@ -23747,7 +23756,7 @@ void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected,
void ResamplingAudioSource::releaseResources() void ResamplingAudioSource::releaseResources()
{ {
input->releaseResources(); input->releaseResources();
buffer.setSize (2, 0);
buffer.setSize (numChannels, 0);
} }


void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info)
@@ -23793,7 +23802,7 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf
{ {
// for down-sampling, pre-apply the filter.. // 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]); applyFilter (buffer.getSampleData (i, endOfBufferPos), numToDo, filterStates[i]);
} }


@@ -23801,23 +23810,20 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf
endOfBufferPos += numToDo; 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; int nextPos = (bufferPos + 1) % bufferSize;

for (int m = info.numSamples; --m >= 0;) for (int m = info.numSamples; --m >= 0;)
{ {
const float alpha = (float) subSampleOffset; const float alpha = (float) subSampleOffset;
const float invAlpha = 1.0f - alpha; 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; subSampleOffset += ratio;


@@ -23838,14 +23844,13 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf
if (ratio < 0.9999) if (ratio < 0.9999)
{ {
// for up-sampling, apply the filter after transposing.. // 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]); applyFilter (info.buffer->getSampleData (i, info.startSample), info.numSamples, filterStates[i]);
} }
else if (ratio <= 1.0001) 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 // 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); const float* const endOfBuffer = info.buffer->getSampleData (i, info.startSample + info.numSamples - 1);
FilterState& fs = filterStates[i]; FilterState& fs = filterStates[i];
@@ -23904,7 +23909,7 @@ void ResamplingAudioSource::setFilterCoefficients (double c1, double c2, double


void ResamplingAudioSource::resetFilters() void ResamplingAudioSource::resetFilters()
{ {
zeromem (filterStates, sizeof (filterStates));
zeromem (filterStates, sizeof (FilterState) * numChannels);
} }


void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs) void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs)
@@ -26166,7 +26171,7 @@ void AudioSampleBuffer::readFromAudioReader (AudioFormatReader* reader,
const int numSamples, const int numSamples,
const int readerStartSample, const int readerStartSample,
const bool useLeftChan, const bool useLeftChan,
const bool useRightChan) throw()
const bool useRightChan)
{ {
jassert (reader != 0); jassert (reader != 0);
jassert (startSample >= 0 && startSample + numSamples <= size); jassert (startSample >= 0 && startSample + numSamples <= size);
@@ -26223,62 +26228,46 @@ void AudioSampleBuffer::readFromAudioReader (AudioFormatReader* reader,


void AudioSampleBuffer::writeToAudioWriter (AudioFormatWriter* writer, void AudioSampleBuffer::writeToAudioWriter (AudioFormatWriter* writer,
const int startSample, 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) if (numSamples > 0)
{ {
int* chans [3];
HeapBlock<int> tempBuffer;
HeapBlock<int*> chans (numChannels + 1);
chans [numChannels] = 0;


if (writer->isFloatingPoint()) 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 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); setSize (400, 600);
list.addChangeListener (this); list.addChangeListener (this);
changeListenerCallback (0);
} }


PluginListComponent::~PluginListComponent() PluginListComponent::~PluginListComponent()
@@ -50950,14 +50940,6 @@ public:
return String::empty; return String::empty;
} }


juce_UseDebuggingNewOperator

private:
TableListBox& owner;
int row;
bool isSelected, isDragging, selectRowOnMouseUp;
BigInteger columnsWithComponents;

Component* findChildComponentForColumn (const int columnId) const Component* findChildComponentForColumn (const int columnId) const
{ {
for (int i = getNumChildComponents(); --i >= 0;) for (int i = getNumChildComponents(); --i >= 0;)
@@ -50971,6 +50953,14 @@ private:
return 0; return 0;
} }


juce_UseDebuggingNewOperator

private:
TableListBox& owner;
int row;
bool isSelected, isDragging, selectRowOnMouseUp;
BigInteger columnsWithComponents;

TableListRowComp (const TableListRowComp&); TableListRowComp (const TableListRowComp&);
TableListRowComp& operator= (const TableListRowComp&); TableListRowComp& operator= (const TableListRowComp&);
}; };
@@ -51102,6 +51092,12 @@ const Rectangle<int> TableListBox::getCellPosition (const int columnId,
headerCell.getWidth(), row.getHeight()); 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) void TableListBox::scrollToEnsureColumnIsOnscreen (const int columnId)
{ {
ScrollBar* const scrollbar = getHorizontalScrollBar(); ScrollBar* const scrollbar = getHorizontalScrollBar();
@@ -85775,10 +85771,10 @@ static const Point<float> findQuadraticSubdivisionPoint (double proportion, cons
return mid1 + (mid2 - mid1) * proportion; 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()); const Identifier i (state.getType());
double bestProp = 0;


if (i == cubicToElement) 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) }; 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(); float bestDistance = std::numeric_limits<float>::max();


for (int i = 110; --i >= 0;) for (int i = 110; --i >= 0;)
@@ -85801,6 +85796,48 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<floa
bestDistance = distance; 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), const Point<float> mid1 (points[0] + (points[1] - points[0]) * bestProp),
mid2 (points[1] + (points[2] - points[1]) * 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) 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) }; 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), const Point<float> mid1 (points[0] + (points[1] - points[0]) * bestProp),
mid2 (points[1] + (points[2] - points[1]) * bestProp); mid2 (points[1] + (points[2] - points[1]) * bestProp);




+ 21
- 9
juce_amalgamated.h View File

@@ -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 30
#define JUCE_BUILDNUMBER 31


/** Current Juce version number. /** Current Juce version number.


@@ -29669,7 +29669,7 @@ public:
int numSamples, int numSamples,
int readerStartSample, int readerStartSample,
bool useReaderLeftChan, bool useReaderLeftChan,
bool useReaderRightChan) throw();
bool useReaderRightChan);


/** Writes a section of this buffer to an audio writer. /** Writes a section of this buffer to an audio writer.


@@ -29680,7 +29680,7 @@ public:
*/ */
void writeToAudioWriter (AudioFormatWriter* writer, void writeToAudioWriter (AudioFormatWriter* writer,
int startSample, int startSample,
int numSamples) const throw();
int numSamples) const;


juce_UseDebuggingNewOperator juce_UseDebuggingNewOperator


@@ -31739,9 +31739,11 @@ public:
@param inputSource the input source to read from @param inputSource the input source to read from
@param deleteInputWhenDeleted if true, the input source will be deleted when @param deleteInputWhenDeleted if true, the input source will be deleted when
this object is deleted this object is deleted
@param numChannels the number of channels to process
*/ */
ResamplingAudioSource (AudioSource* const inputSource, ResamplingAudioSource (AudioSource* const inputSource,
const bool deleteInputWhenDeleted);
const bool deleteInputWhenDeleted,
int numChannels = 2);


/** Destructor. */ /** Destructor. */
~ResamplingAudioSource(); ~ResamplingAudioSource();
@@ -31777,6 +31779,8 @@ private:
double subSampleOffset; double subSampleOffset;
double coefficients[6]; double coefficients[6];
CriticalSection ratioLock; CriticalSection ratioLock;
const int numChannels;
HeapBlock<float*> destBuffers, srcBuffers;


void setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6); void setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6);
void createLowPass (const double proportionalRate); void createLowPass (const double proportionalRate);
@@ -31786,7 +31790,7 @@ private:
double x1, x2, y1, y2; double x1, x2, y1, y2;
}; };


FilterState filterStates[2];
HeapBlock<FilterState> filterStates;
void resetFilters(); void resetFilters();


void applyFilter (float* samples, int num, FilterState& fs); void applyFilter (float* samples, int num, FilterState& fs);
@@ -36664,6 +36668,9 @@ public:
*/ */
void showEditor(); void showEditor();


/** Pops up the combo box's list. */
void showPopup();

/** Registers a listener that will be called when the box's content changes. */ /** Registers a listener that will be called when the box's content changes. */
void addListener (ComboBoxListener* listener) throw(); void addListener (ComboBoxListener* listener) throw();


@@ -36773,8 +36780,6 @@ private:
ScopedPointer<Label> label; ScopedPointer<Label> label;
String textWhenNothingSelected, noChoicesMessage; String textWhenNothingSelected, noChoicesMessage;


void showPopup();

ItemInfo* getItemForId (int itemId) const throw(); ItemInfo* getItemForId (int itemId) const throw();
ItemInfo* getItemForIndex (int index) const throw(); ItemInfo* getItemForIndex (int index) const throw();


@@ -47165,10 +47170,16 @@ public:
If relativeToComponentTopLeft is false, the co-ords are relative to the If relativeToComponentTopLeft is false, the co-ords are relative to the
top-left of the table's top-left cell. 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; 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. /** Scrolls horizontally if necessary to make sure that a particular column is visible.


@see ListBox::scrollToEnsureRowIsOnscreen @see ListBox::scrollToEnsureRowIsOnscreen
@@ -59405,6 +59416,7 @@ public:
void convertToPathBreak (UndoManager* undoManager); void convertToPathBreak (UndoManager* undoManager);
ValueTree insertPoint (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager); ValueTree insertPoint (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager);
void removePoint (UndoManager* undoManager); void removePoint (UndoManager* undoManager);
double findProportionAlongLine (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder) const;


static const Identifier mode, startSubPathElement, closeSubPathElement, static const Identifier mode, startSubPathElement, closeSubPathElement,
lineToElement, quadraticToElement, cubicToElement; lineToElement, quadraticToElement, cubicToElement;


+ 21
- 20
src/audio/audio_sources/juce_ResamplingAudioSource.cpp View File

@@ -33,13 +33,15 @@ BEGIN_JUCE_NAMESPACE
//============================================================================== //==============================================================================
ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource, ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource,
const bool deleteInputWhenDeleted_)
const bool deleteInputWhenDeleted_,
const int numChannels_)
: input (inputSource), : input (inputSource),
deleteInputWhenDeleted (deleteInputWhenDeleted_), deleteInputWhenDeleted (deleteInputWhenDeleted_),
ratio (1.0), ratio (1.0),
lastRatio (1.0), lastRatio (1.0),
buffer (2, 0),
sampsInBuffer (0)
buffer (numChannels_, 0),
sampsInBuffer (0),
numChannels (numChannels_)
{ {
jassert (input != 0); jassert (input != 0);
} }
@@ -65,12 +67,15 @@ void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected,
input->prepareToPlay (samplesPerBlockExpected, sampleRate); input->prepareToPlay (samplesPerBlockExpected, sampleRate);
buffer.setSize (2, roundToInt (samplesPerBlockExpected * ratio) + 32);
buffer.setSize (numChannels, roundToInt (samplesPerBlockExpected * ratio) + 32);
buffer.clear(); buffer.clear();
sampsInBuffer = 0; sampsInBuffer = 0;
bufferPos = 0; bufferPos = 0;
subSampleOffset = 0.0; subSampleOffset = 0.0;
filterStates.calloc (numChannels);
srcBuffers.calloc (numChannels);
destBuffers.calloc (numChannels);
createLowPass (ratio); createLowPass (ratio);
resetFilters(); resetFilters();
} }
@@ -78,7 +83,7 @@ void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected,
void ResamplingAudioSource::releaseResources() void ResamplingAudioSource::releaseResources()
{ {
input->releaseResources(); input->releaseResources();
buffer.setSize (2, 0);
buffer.setSize (numChannels, 0);
} }
void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info)
@@ -124,7 +129,7 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf
{ {
// for down-sampling, pre-apply the filter.. // 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]); applyFilter (buffer.getSampleData (i, endOfBufferPos), numToDo, filterStates[i]);
} }
@@ -132,23 +137,20 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf
endOfBufferPos += numToDo; 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; int nextPos = (bufferPos + 1) % bufferSize;
for (int m = info.numSamples; --m >= 0;) for (int m = info.numSamples; --m >= 0;)
{ {
const float alpha = (float) subSampleOffset; const float alpha = (float) subSampleOffset;
const float invAlpha = 1.0f - alpha; 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; subSampleOffset += ratio;
@@ -169,14 +171,13 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf
if (ratio < 0.9999) if (ratio < 0.9999)
{ {
// for up-sampling, apply the filter after transposing.. // 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]); applyFilter (info.buffer->getSampleData (i, info.startSample), info.numSamples, filterStates[i]);
} }
else if (ratio <= 1.0001) 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 // 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); const float* const endOfBuffer = info.buffer->getSampleData (i, info.startSample + info.numSamples - 1);
FilterState& fs = filterStates[i]; FilterState& fs = filterStates[i];
@@ -235,7 +236,7 @@ void ResamplingAudioSource::setFilterCoefficients (double c1, double c2, double
void ResamplingAudioSource::resetFilters() void ResamplingAudioSource::resetFilters()
{ {
zeromem (filterStates, sizeof (filterStates));
zeromem (filterStates, sizeof (FilterState) * numChannels);
} }
void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs) void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs)


+ 7
- 2
src/audio/audio_sources/juce_ResamplingAudioSource.h View File

@@ -29,6 +29,7 @@
#include "juce_AudioSource.h" #include "juce_AudioSource.h"
#include "../../threads/juce_CriticalSection.h" #include "../../threads/juce_CriticalSection.h"
//============================================================================== //==============================================================================
/** /**
A type of AudioSource that takes an input source and changes its sample rate. 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 inputSource the input source to read from
@param deleteInputWhenDeleted if true, the input source will be deleted when @param deleteInputWhenDeleted if true, the input source will be deleted when
this object is deleted this object is deleted
@param numChannels the number of channels to process
*/ */
ResamplingAudioSource (AudioSource* const inputSource, ResamplingAudioSource (AudioSource* const inputSource,
const bool deleteInputWhenDeleted);
const bool deleteInputWhenDeleted,
int numChannels = 2);
/** Destructor. */ /** Destructor. */
~ResamplingAudioSource(); ~ResamplingAudioSource();
@@ -84,6 +87,8 @@ private:
double subSampleOffset; double subSampleOffset;
double coefficients[6]; double coefficients[6];
CriticalSection ratioLock; CriticalSection ratioLock;
const int numChannels;
HeapBlock<float*> destBuffers, srcBuffers;
void setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6); void setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6);
void createLowPass (const double proportionalRate); void createLowPass (const double proportionalRate);
@@ -93,7 +98,7 @@ private:
double x1, x2, y1, y2; double x1, x2, y1, y2;
}; };
FilterState filterStates[2];
HeapBlock<FilterState> filterStates;
void resetFilters(); void resetFilters();
void applyFilter (float* samples, int num, FilterState& fs); void applyFilter (float* samples, int num, FilterState& fs);


+ 24
- 40
src/audio/dsp/juce_AudioSampleBuffer.cpp View File

@@ -574,7 +574,7 @@ void AudioSampleBuffer::readFromAudioReader (AudioFormatReader* reader,
const int numSamples, const int numSamples,
const int readerStartSample, const int readerStartSample,
const bool useLeftChan, const bool useLeftChan,
const bool useRightChan) throw()
const bool useRightChan)
{ {
jassert (reader != 0); jassert (reader != 0);
jassert (startSample >= 0 && startSample + numSamples <= size); jassert (startSample >= 0 && startSample + numSamples <= size);
@@ -631,62 +631,46 @@ void AudioSampleBuffer::readFromAudioReader (AudioFormatReader* reader,
void AudioSampleBuffer::writeToAudioWriter (AudioFormatWriter* writer, void AudioSampleBuffer::writeToAudioWriter (AudioFormatWriter* writer,
const int startSample, 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) if (numSamples > 0)
{ {
int* chans [3];
HeapBlock<int> tempBuffer;
HeapBlock<int*> chans (numChannels + 1);
chans [numChannels] = 0;
if (writer->isFloatingPoint()) 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 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);
} }
} }


+ 2
- 2
src/audio/dsp/juce_AudioSampleBuffer.h View File

@@ -407,7 +407,7 @@ public:
int numSamples, int numSamples,
int readerStartSample, int readerStartSample,
bool useReaderLeftChan, bool useReaderLeftChan,
bool useReaderRightChan) throw();
bool useReaderRightChan);
/** Writes a section of this buffer to an audio writer. /** Writes a section of this buffer to an audio writer.
@@ -418,7 +418,7 @@ public:
*/ */
void writeToAudioWriter (AudioFormatWriter* writer, void writeToAudioWriter (AudioFormatWriter* writer,
int startSample, int startSample,
int numSamples) const throw();
int numSamples) const;
//============================================================================== //==============================================================================
juce_UseDebuggingNewOperator juce_UseDebuggingNewOperator


+ 1
- 0
src/audio/plugins/juce_PluginListComponent.cpp View File

@@ -53,6 +53,7 @@ PluginListComponent::PluginListComponent (KnownPluginList& listToEdit,
setSize (400, 600); setSize (400, 600);
list.addChangeListener (this); list.addChangeListener (this);
changeListenerCallback (0);
} }
PluginListComponent::~PluginListComponent() PluginListComponent::~PluginListComponent()


+ 1
- 1
src/core/juce_StandardHeader.h View File

@@ -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 30
#define JUCE_BUILDNUMBER 31
/** Current Juce version number. /** Current Juce version number.


+ 3
- 2
src/gui/components/controls/juce_ComboBox.h View File

@@ -282,6 +282,9 @@ public:
*/ */
void showEditor(); void showEditor();
/** Pops up the combo box's list. */
void showPopup();
//============================================================================== //==============================================================================
/** Registers a listener that will be called when the box's content changes. */ /** Registers a listener that will be called when the box's content changes. */
void addListener (ComboBoxListener* listener) throw(); void addListener (ComboBoxListener* listener) throw();
@@ -399,8 +402,6 @@ private:
ScopedPointer<Label> label; ScopedPointer<Label> label;
String textWhenNothingSelected, noChoicesMessage; String textWhenNothingSelected, noChoicesMessage;
void showPopup();
ItemInfo* getItemForId (int itemId) const throw(); ItemInfo* getItemForId (int itemId) const throw();
ItemInfo* getItemForIndex (int index) const throw(); ItemInfo* getItemForIndex (int index) const throw();


+ 14
- 8
src/gui/components/controls/juce_TableListBox.cpp View File

@@ -237,14 +237,6 @@ public:
return String::empty; return String::empty;
} }
juce_UseDebuggingNewOperator
private:
TableListBox& owner;
int row;
bool isSelected, isDragging, selectRowOnMouseUp;
BigInteger columnsWithComponents;
Component* findChildComponentForColumn (const int columnId) const Component* findChildComponentForColumn (const int columnId) const
{ {
for (int i = getNumChildComponents(); --i >= 0;) for (int i = getNumChildComponents(); --i >= 0;)
@@ -258,6 +250,14 @@ private:
return 0; return 0;
} }
juce_UseDebuggingNewOperator
private:
TableListBox& owner;
int row;
bool isSelected, isDragging, selectRowOnMouseUp;
BigInteger columnsWithComponents;
TableListRowComp (const TableListRowComp&); TableListRowComp (const TableListRowComp&);
TableListRowComp& operator= (const TableListRowComp&); TableListRowComp& operator= (const TableListRowComp&);
}; };
@@ -392,6 +392,12 @@ const Rectangle<int> TableListBox::getCellPosition (const int columnId,
headerCell.getWidth(), row.getHeight()); 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) void TableListBox::scrollToEnsureColumnIsOnscreen (const int columnId)
{ {
ScrollBar* const scrollbar = getHorizontalScrollBar(); ScrollBar* const scrollbar = getHorizontalScrollBar();


+ 8
- 2
src/gui/components/controls/juce_TableListBox.h View File

@@ -269,10 +269,16 @@ public:
If relativeToComponentTopLeft is false, the co-ords are relative to the If relativeToComponentTopLeft is false, the co-ords are relative to the
top-left of the table's top-left cell. 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; 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. /** Scrolls horizontally if necessary to make sure that a particular column is visible.
@see ListBox::scrollToEnsureRowIsOnscreen @see ListBox::scrollToEnsureRowIsOnscreen


+ 46
- 20
src/gui/graphics/drawables/juce_DrawablePath.cpp View File

@@ -473,10 +473,10 @@ static const Point<float> findQuadraticSubdivisionPoint (double proportion, cons
return mid1 + (mid2 - mid1) * proportion; 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()); const Identifier i (state.getType());
double bestProp = 0;
if (i == cubicToElement) 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) }; 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(); float bestDistance = std::numeric_limits<float>::max();
for (int i = 110; --i >= 0;) for (int i = 110; --i >= 0;)
@@ -499,6 +498,48 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<floa
bestDistance = distance; 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), const Point<float> mid1 (points[0] + (points[1] - points[0]) * bestProp),
mid2 (points[1] + (points[2] - points[1]) * 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) 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) }; 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), const Point<float> mid1 (points[0] + (points[1] - points[0]) * bestProp),
mid2 (points[1] + (points[2] - points[1]) * bestProp); mid2 (points[1] + (points[2] - points[1]) * bestProp);


+ 1
- 0
src/gui/graphics/drawables/juce_DrawablePath.h View File

@@ -176,6 +176,7 @@ public:
void convertToPathBreak (UndoManager* undoManager); void convertToPathBreak (UndoManager* undoManager);
ValueTree insertPoint (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager); ValueTree insertPoint (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager);
void removePoint (UndoManager* undoManager); void removePoint (UndoManager* undoManager);
double findProportionAlongLine (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder) const;
static const Identifier mode, startSubPathElement, closeSubPathElement, static const Identifier mode, startSubPathElement, closeSubPathElement,
lineToElement, quadraticToElement, cubicToElement; lineToElement, quadraticToElement, cubicToElement;


+ 4
- 0
src/text/juce_String.cpp View File

@@ -1928,6 +1928,10 @@ const char* String::toUTF8() const
mutableThis->text = StringHolder::makeUniqueWithSize (mutableThis->text, currentLen + 1 + utf8BytesNeeded / sizeof (juce_wchar)); mutableThis->text = StringHolder::makeUniqueWithSize (mutableThis->text, currentLen + 1 + utf8BytesNeeded / sizeof (juce_wchar));
char* const otherCopy = reinterpret_cast <char*> (mutableThis->text + currentLen); 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()); copyToUTF8 (otherCopy, std::numeric_limits<int>::max());
return otherCopy; return otherCopy;


Loading…
Cancel
Save