Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -0,0 +1,104 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/

#ifndef __JUCE_DECIBELS_JUCEHEADER__
#define __JUCE_DECIBELS_JUCEHEADER__

//==============================================================================
/**
This class contains some helpful static methods for dealing with decibel values.
*/
class Decibels
{
public:
//==============================================================================
/** Converts a dBFS value to its equivalent gain level.
A gain of 1.0 = 0 dB, and lower gains map onto negative decibel values. Any
decibel value lower than minusInfinityDb will return a gain of 0.
*/
template <typename Type>
static Type decibelsToGain (const Type decibels,
const Type minusInfinityDb = (Type) defaultMinusInfinitydB)
{
return decibels > minusInfinityDb ? powf ((Type) 10.0, decibels * (Type) 0.05)
: Type();
}

/** Converts a gain level into a dBFS value.
A gain of 1.0 = 0 dB, and lower gains map onto negative decibel values.
If the gain is 0 (or negative), then the method will return the value
provided as minusInfinityDb.
*/
template <typename Type>
static Type gainToDecibels (const Type gain,
const Type minusInfinityDb = (Type) defaultMinusInfinitydB)
{
return gain > Type() ? jmax (minusInfinityDb, (Type) std::log10 (gain) * (Type) 20.0)
: minusInfinityDb;
}

//==============================================================================
/** Converts a decibel reading to a string, with the 'dB' suffix.
If the decibel value is lower than minusInfinityDb, the return value will
be "-INF dB".
*/
template <typename Type>
static String toString (const Type decibels,
const int decimalPlaces = 2,
const Type minusInfinityDb = (Type) defaultMinusInfinitydB)
{
String s;

if (decibels <= minusInfinityDb)
{
s = "-INF dB";
}
else
{
if (decibels >= Type())
s << '+';

s << String (decibels, decimalPlaces) << " dB";
}

return s;
}


private:
//==============================================================================
enum
{
defaultMinusInfinitydB = -100
};

Decibels(); // This class can't be instantiated, it's just a holder for static methods..
JUCE_DECLARE_NON_COPYABLE (Decibels)
};


#endif // __JUCE_DECIBELS_JUCEHEADER__
@@ -0,0 +1,252 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/

#if JUCE_INTEL
#define JUCE_SNAP_TO_ZERO(n) if (! (n < -1.0e-8 || n > 1.0e-8)) n = 0;
#else
#define JUCE_SNAP_TO_ZERO(n)
#endif

//==============================================================================
IIRFilter::IIRFilter()
: active (false)
{
reset();
}

IIRFilter::IIRFilter (const IIRFilter& other)
: active (other.active)
{
const ScopedLock sl (other.processLock);
memcpy (coefficients, other.coefficients, sizeof (coefficients));
reset();
}

IIRFilter::~IIRFilter()
{
}

//==============================================================================
void IIRFilter::reset() noexcept
{
const ScopedLock sl (processLock);

x1 = 0;
x2 = 0;
y1 = 0;
y2 = 0;
}

float IIRFilter::processSingleSampleRaw (const float in) noexcept
{
float out = coefficients[0] * in
+ coefficients[1] * x1
+ coefficients[2] * x2
- coefficients[4] * y1
- coefficients[5] * y2;

JUCE_SNAP_TO_ZERO (out);

x2 = x1;
x1 = in;
y2 = y1;
y1 = out;

return out;
}

void IIRFilter::processSamples (float* const samples,
const int numSamples) noexcept
{
const ScopedLock sl (processLock);

if (active)
{
for (int i = 0; i < numSamples; ++i)
{
const float in = samples[i];

float out = coefficients[0] * in
+ coefficients[1] * x1
+ coefficients[2] * x2
- coefficients[4] * y1
- coefficients[5] * y2;

JUCE_SNAP_TO_ZERO (out);

x2 = x1;
x1 = in;
y2 = y1;
y1 = out;

samples[i] = out;
}
}
}

//==============================================================================
void IIRFilter::makeLowPass (const double sampleRate,
const double frequency) noexcept
{
jassert (sampleRate > 0);

const double n = 1.0 / tan (double_Pi * frequency / sampleRate);
const double nSquared = n * n;
const double c1 = 1.0 / (1.0 + std::sqrt (2.0) * n + nSquared);

setCoefficients (c1,
c1 * 2.0f,
c1,
1.0,
c1 * 2.0 * (1.0 - nSquared),
c1 * (1.0 - std::sqrt (2.0) * n + nSquared));
}

void IIRFilter::makeHighPass (const double sampleRate,
const double frequency) noexcept
{
const double n = tan (double_Pi * frequency / sampleRate);
const double nSquared = n * n;
const double c1 = 1.0 / (1.0 + std::sqrt (2.0) * n + nSquared);

setCoefficients (c1,
c1 * -2.0f,
c1,
1.0,
c1 * 2.0 * (nSquared - 1.0),
c1 * (1.0 - std::sqrt (2.0) * n + nSquared));
}

void IIRFilter::makeLowShelf (const double sampleRate,
const double cutOffFrequency,
const double Q,
const float gainFactor) noexcept
{
jassert (sampleRate > 0);
jassert (Q > 0);

const double A = jmax (0.0f, gainFactor);
const double aminus1 = A - 1.0;
const double aplus1 = A + 1.0;
const double omega = (double_Pi * 2.0 * jmax (cutOffFrequency, 2.0)) / sampleRate;
const double coso = std::cos (omega);
const double beta = std::sin (omega) * std::sqrt (A) / Q;
const double aminus1TimesCoso = aminus1 * coso;

setCoefficients (A * (aplus1 - aminus1TimesCoso + beta),
A * 2.0 * (aminus1 - aplus1 * coso),
A * (aplus1 - aminus1TimesCoso - beta),
aplus1 + aminus1TimesCoso + beta,
-2.0 * (aminus1 + aplus1 * coso),
aplus1 + aminus1TimesCoso - beta);
}

void IIRFilter::makeHighShelf (const double sampleRate,
const double cutOffFrequency,
const double Q,
const float gainFactor) noexcept
{
jassert (sampleRate > 0);
jassert (Q > 0);

const double A = jmax (0.0f, gainFactor);
const double aminus1 = A - 1.0;
const double aplus1 = A + 1.0;
const double omega = (double_Pi * 2.0 * jmax (cutOffFrequency, 2.0)) / sampleRate;
const double coso = std::cos (omega);
const double beta = std::sin (omega) * std::sqrt (A) / Q;
const double aminus1TimesCoso = aminus1 * coso;

setCoefficients (A * (aplus1 + aminus1TimesCoso + beta),
A * -2.0 * (aminus1 + aplus1 * coso),
A * (aplus1 + aminus1TimesCoso - beta),
aplus1 - aminus1TimesCoso + beta,
2.0 * (aminus1 - aplus1 * coso),
aplus1 - aminus1TimesCoso - beta);
}

void IIRFilter::makeBandPass (const double sampleRate,
const double centreFrequency,
const double Q,
const float gainFactor) noexcept
{
jassert (sampleRate > 0);
jassert (Q > 0);

const double A = jmax (0.0f, gainFactor);
const double omega = (double_Pi * 2.0 * jmax (centreFrequency, 2.0)) / sampleRate;
const double alpha = 0.5 * std::sin (omega) / Q;
const double c2 = -2.0 * std::cos (omega);
const double alphaTimesA = alpha * A;
const double alphaOverA = alpha / A;

setCoefficients (1.0 + alphaTimesA,
c2,
1.0 - alphaTimesA,
1.0 + alphaOverA,
c2,
1.0 - alphaOverA);
}

void IIRFilter::makeInactive() noexcept
{
const ScopedLock sl (processLock);
active = false;
}

//==============================================================================
void IIRFilter::copyCoefficientsFrom (const IIRFilter& other) noexcept
{
const ScopedLock sl (processLock);

memcpy (coefficients, other.coefficients, sizeof (coefficients));
active = other.active;
}

//==============================================================================
void IIRFilter::setCoefficients (double c1, double c2, double c3,
double c4, double c5, double c6) noexcept
{
const double a = 1.0 / c4;

c1 *= a;
c2 *= a;
c3 *= a;
c5 *= a;
c6 *= a;

const ScopedLock sl (processLock);

coefficients[0] = (float) c1;
coefficients[1] = (float) c2;
coefficients[2] = (float) c3;
coefficients[3] = (float) c4;
coefficients[4] = (float) c5;
coefficients[5] = (float) c6;

active = true;
}

#undef JUCE_SNAP_TO_ZERO
@@ -0,0 +1,149 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/

#ifndef __JUCE_IIRFILTER_JUCEHEADER__
#define __JUCE_IIRFILTER_JUCEHEADER__


//==============================================================================
/**
An IIR filter that can perform low, high, or band-pass filtering on an
audio signal.
@see IIRFilterAudioSource
*/
class JUCE_API IIRFilter
{
public:
//==============================================================================
/** Creates a filter.
Initially the filter is inactive, so will have no effect on samples that
you process with it. Use the appropriate method to turn it into the type
of filter needed.
*/
IIRFilter();

/** Creates a copy of another filter. */
IIRFilter (const IIRFilter& other);

/** Destructor. */
~IIRFilter();

//==============================================================================
/** Resets the filter's processing pipeline, ready to start a new stream of data.
Note that this clears the processing state, but the type of filter and
its coefficients aren't changed. To put a filter into an inactive state, use
the makeInactive() method.
*/
void reset() noexcept;

/** Performs the filter operation on the given set of samples.
*/
void processSamples (float* samples,
int numSamples) noexcept;

/** Processes a single sample, without any locking or checking.
Use this if you need fast processing of a single value, but be aware that
this isn't thread-safe in the way that processSamples() is.
*/
float processSingleSampleRaw (float sample) noexcept;

//==============================================================================
/** Sets the filter up to act as a low-pass filter.
*/
void makeLowPass (double sampleRate,
double frequency) noexcept;

/** Sets the filter up to act as a high-pass filter.
*/
void makeHighPass (double sampleRate,
double frequency) noexcept;

//==============================================================================
/** Sets the filter up to act as a low-pass shelf filter with variable Q and gain.
The gain is a scale factor that the low frequencies are multiplied by, so values
greater than 1.0 will boost the low frequencies, values less than 1.0 will
attenuate them.
*/
void makeLowShelf (double sampleRate,
double cutOffFrequency,
double Q,
float gainFactor) noexcept;

/** Sets the filter up to act as a high-pass shelf filter with variable Q and gain.
The gain is a scale factor that the high frequencies are multiplied by, so values
greater than 1.0 will boost the high frequencies, values less than 1.0 will
attenuate them.
*/
void makeHighShelf (double sampleRate,
double cutOffFrequency,
double Q,
float gainFactor) noexcept;

/** Sets the filter up to act as a band pass filter centred around a
frequency, with a variable Q and gain.
The gain is a scale factor that the centre frequencies are multiplied by, so
values greater than 1.0 will boost the centre frequencies, values less than
1.0 will attenuate them.
*/
void makeBandPass (double sampleRate,
double centreFrequency,
double Q,
float gainFactor) noexcept;

/** Clears the filter's coefficients so that it becomes inactive.
*/
void makeInactive() noexcept;

//==============================================================================
/** Makes this filter duplicate the set-up of another one.
*/
void copyCoefficientsFrom (const IIRFilter& other) noexcept;


protected:
//==============================================================================
CriticalSection processLock;

void setCoefficients (double c1, double c2, double c3,
double c4, double c5, double c6) noexcept;

bool active;
float coefficients[6];
float x1, x2, y1, y2;

// (use the copyCoefficientsFrom() method instead of this operator)
IIRFilter& operator= (const IIRFilter&);
JUCE_LEAK_DETECTOR (IIRFilter)
};


#endif // __JUCE_IIRFILTER_JUCEHEADER__
@@ -0,0 +1,321 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/

#ifndef __JUCE_REVERB_JUCEHEADER__
#define __JUCE_REVERB_JUCEHEADER__


//==============================================================================
/**
Performs a simple reverb effect on a stream of audio data.
This is a simple stereo reverb, based on the technique and tunings used in FreeVerb.
Use setSampleRate() to prepare it, and then call processStereo() or processMono() to
apply the reverb to your audio data.
@see ReverbAudioSource
*/
class Reverb
{
public:
//==============================================================================
Reverb()
{
setParameters (Parameters());
setSampleRate (44100.0);
}

//==============================================================================
/** Holds the parameters being used by a Reverb object. */
struct Parameters
{
Parameters() noexcept
: roomSize (0.5f),
damping (0.5f),
wetLevel (0.33f),
dryLevel (0.4f),
width (1.0f),
freezeMode (0)
{}

float roomSize; /**< Room size, 0 to 1.0, where 1.0 is big, 0 is small. */
float damping; /**< Damping, 0 to 1.0, where 0 is not damped, 1.0 is fully damped. */
float wetLevel; /**< Wet level, 0 to 1.0 */
float dryLevel; /**< Dry level, 0 to 1.0 */
float width; /**< Reverb width, 0 to 1.0, where 1.0 is very wide. */
float freezeMode; /**< Freeze mode - values < 0.5 are "normal" mode, values > 0.5
put the reverb into a continuous feedback loop. */
};

//==============================================================================
/** Returns the reverb's current parameters. */
const Parameters& getParameters() const noexcept { return parameters; }

/** Applies a new set of parameters to the reverb.
Note that this doesn't attempt to lock the reverb, so if you call this in parallel with
the process method, you may get artifacts.
*/
void setParameters (const Parameters& newParams)
{
const float wetScaleFactor = 3.0f;
const float dryScaleFactor = 2.0f;

const float wet = newParams.wetLevel * wetScaleFactor;
wet1 = wet * (newParams.width * 0.5f + 0.5f);
wet2 = wet * (1.0f - newParams.width) * 0.5f;
dry = newParams.dryLevel * dryScaleFactor;
gain = isFrozen (newParams.freezeMode) ? 0.0f : 0.015f;
parameters = newParams;
shouldUpdateDamping = true;
}

//==============================================================================
/** Sets the sample rate that will be used for the reverb.
You must call this before the process methods, in order to tell it the correct sample rate.
*/
void setSampleRate (const double sampleRate)
{
jassert (sampleRate > 0);

static const short combTunings[] = { 1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 }; // (at 44100Hz)
static const short allPassTunings[] = { 556, 441, 341, 225 };
const int stereoSpread = 23;
const int intSampleRate = (int) sampleRate;

for (int i = 0; i < numCombs; ++i)
{
comb[0][i].setSize ((intSampleRate * combTunings[i]) / 44100);
comb[1][i].setSize ((intSampleRate * (combTunings[i] + stereoSpread)) / 44100);
}

for (int i = 0; i < numAllPasses; ++i)
{
allPass[0][i].setSize ((intSampleRate * allPassTunings[i]) / 44100);
allPass[1][i].setSize ((intSampleRate * (allPassTunings[i] + stereoSpread)) / 44100);
}

shouldUpdateDamping = true;
}

/** Clears the reverb's buffers. */
void reset()
{
for (int j = 0; j < numChannels; ++j)
{
for (int i = 0; i < numCombs; ++i)
comb[j][i].clear();

for (int i = 0; i < numAllPasses; ++i)
allPass[j][i].clear();
}
}

//==============================================================================
/** Applies the reverb to two stereo channels of audio data. */
void processStereo (float* const left, float* const right, const int numSamples) noexcept
{
jassert (left != nullptr && right != nullptr);

if (shouldUpdateDamping)
updateDamping();

for (int i = 0; i < numSamples; ++i)
{
const float input = (left[i] + right[i]) * gain;
float outL = 0, outR = 0;

for (int j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel
{
outL += comb[0][j].process (input);
outR += comb[1][j].process (input);
}

for (int j = 0; j < numAllPasses; ++j) // run the allpass filters in series
{
outL = allPass[0][j].process (outL);
outR = allPass[1][j].process (outR);
}

left[i] = outL * wet1 + outR * wet2 + left[i] * dry;
right[i] = outR * wet1 + outL * wet2 + right[i] * dry;
}
}

/** Applies the reverb to a single mono channel of audio data. */
void processMono (float* const samples, const int numSamples) noexcept
{
jassert (samples != nullptr);

if (shouldUpdateDamping)
updateDamping();

for (int i = 0; i < numSamples; ++i)
{
const float input = samples[i] * gain;
float output = 0;

for (int j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel
output += comb[0][j].process (input);

for (int j = 0; j < numAllPasses; ++j) // run the allpass filters in series
output = allPass[0][j].process (output);

samples[i] = output * wet1 + input * dry;
}
}

private:
//==============================================================================
Parameters parameters;

volatile bool shouldUpdateDamping;
float gain, wet1, wet2, dry;

inline static bool isFrozen (const float freezeMode) noexcept { return freezeMode >= 0.5f; }

void updateDamping() noexcept
{
const float roomScaleFactor = 0.28f;
const float roomOffset = 0.7f;
const float dampScaleFactor = 0.4f;

shouldUpdateDamping = false;

if (isFrozen (parameters.freezeMode))
setDamping (0.0f, 1.0f);
else
setDamping (parameters.damping * dampScaleFactor,
parameters.roomSize * roomScaleFactor + roomOffset);
}

void setDamping (const float dampingToUse, const float roomSizeToUse) noexcept
{
for (int j = 0; j < numChannels; ++j)
for (int i = numCombs; --i >= 0;)
comb[j][i].setFeedbackAndDamp (roomSizeToUse, dampingToUse);
}

//==============================================================================
class CombFilter
{
public:
CombFilter() noexcept : bufferSize (0), bufferIndex (0) {}

void setSize (const int size)
{
if (size != bufferSize)
{
bufferIndex = 0;
buffer.malloc ((size_t) size);
bufferSize = size;
}

clear();
}

void clear() noexcept
{
last = 0;
buffer.clear ((size_t) bufferSize);
}

void setFeedbackAndDamp (const float f, const float d) noexcept
{
damp1 = d;
damp2 = 1.0f - d;
feedback = f;
}

inline float process (const float input) noexcept
{
const float output = buffer [bufferIndex];
last = (output * damp2) + (last * damp1);
JUCE_UNDENORMALISE (last);

float temp = input + (last * feedback);
JUCE_UNDENORMALISE (temp);
buffer [bufferIndex] = temp;
bufferIndex = (bufferIndex + 1) % bufferSize;
return output;
}

private:
HeapBlock<float> buffer;
int bufferSize, bufferIndex;
float feedback, last, damp1, damp2;

JUCE_DECLARE_NON_COPYABLE (CombFilter)
};

//==============================================================================
class AllPassFilter
{
public:
AllPassFilter() noexcept : bufferSize (0), bufferIndex (0) {}

void setSize (const int size)
{
if (size != bufferSize)
{
bufferIndex = 0;
buffer.malloc ((size_t) size);
bufferSize = size;
}

clear();
}

void clear() noexcept
{
buffer.clear ((size_t) bufferSize);
}

inline float process (const float input) noexcept
{
const float bufferedValue = buffer [bufferIndex];
float temp = input + (bufferedValue * 0.5f);
JUCE_UNDENORMALISE (temp);
buffer [bufferIndex] = temp;
bufferIndex = (bufferIndex + 1) % bufferSize;
return bufferedValue - input;
}

private:
HeapBlock<float> buffer;
int bufferSize, bufferIndex;

JUCE_DECLARE_NON_COPYABLE (AllPassFilter)
};

enum { numCombs = 8, numAllPasses = 4, numChannels = 2 };

CombFilter comb [numChannels][numCombs];
AllPassFilter allPass [numChannels][numAllPasses];

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Reverb)
};


#endif // __JUCE_REVERB_JUCEHEADER__
@@ -0,0 +1,63 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/

#if defined (__JUCE_AUDIO_BASICS_JUCEHEADER__) && ! JUCE_AMALGAMATED_INCLUDE
/* When you add this cpp file to your project, you mustn't include it in a file where you've
already included any other headers - just put it inside a file on its own, possibly with your config
flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix
header files that the compiler may be using.
*/
#error "Incorrect use of JUCE cpp file"
#endif

// Your project must contain an AppConfig.h file with your project-specific settings in it,
// and your header search path must make it accessible to the module's files.
#include "AppConfig.h"

#include "juce_audio_basics.h"

namespace juce
{

// START_AUTOINCLUDE buffers/*.cpp, effects/*.cpp, midi/*.cpp, sources/*.cpp, synthesisers/*.cpp
#include "buffers/juce_AudioDataConverters.cpp"
#include "buffers/juce_AudioSampleBuffer.cpp"
#include "effects/juce_IIRFilter.cpp"
#include "midi/juce_MidiBuffer.cpp"
#include "midi/juce_MidiFile.cpp"
#include "midi/juce_MidiKeyboardState.cpp"
#include "midi/juce_MidiMessage.cpp"
#include "midi/juce_MidiMessageSequence.cpp"
#include "sources/juce_BufferingAudioSource.cpp"
#include "sources/juce_ChannelRemappingAudioSource.cpp"
#include "sources/juce_IIRFilterAudioSource.cpp"
#include "sources/juce_MixerAudioSource.cpp"
#include "sources/juce_ResamplingAudioSource.cpp"
#include "sources/juce_ReverbAudioSource.cpp"
#include "sources/juce_ToneGeneratorAudioSource.cpp"
#include "synthesisers/juce_Synthesiser.cpp"
// END_AUTOINCLUDE

}
@@ -0,0 +1,100 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/

#ifndef __JUCE_AUDIO_BASICS_JUCEHEADER__
#define __JUCE_AUDIO_BASICS_JUCEHEADER__

#include "../juce_core/juce_core.h"

//=============================================================================
namespace juce
{

// START_AUTOINCLUDE buffers, effects, midi, sources, synthesisers
#ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__
#include "buffers/juce_AudioDataConverters.h"
#endif
#ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__
#include "buffers/juce_AudioSampleBuffer.h"
#endif
#ifndef __JUCE_DECIBELS_JUCEHEADER__
#include "effects/juce_Decibels.h"
#endif
#ifndef __JUCE_IIRFILTER_JUCEHEADER__
#include "effects/juce_IIRFilter.h"
#endif
#ifndef __JUCE_REVERB_JUCEHEADER__
#include "effects/juce_Reverb.h"
#endif
#ifndef __JUCE_MIDIBUFFER_JUCEHEADER__
#include "midi/juce_MidiBuffer.h"
#endif
#ifndef __JUCE_MIDIFILE_JUCEHEADER__
#include "midi/juce_MidiFile.h"
#endif
#ifndef __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__
#include "midi/juce_MidiKeyboardState.h"
#endif
#ifndef __JUCE_MIDIMESSAGE_JUCEHEADER__
#include "midi/juce_MidiMessage.h"
#endif
#ifndef __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__
#include "midi/juce_MidiMessageSequence.h"
#endif
#ifndef __JUCE_AUDIOSOURCE_JUCEHEADER__
#include "sources/juce_AudioSource.h"
#endif
#ifndef __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__
#include "sources/juce_BufferingAudioSource.h"
#endif
#ifndef __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__
#include "sources/juce_ChannelRemappingAudioSource.h"
#endif
#ifndef __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__
#include "sources/juce_IIRFilterAudioSource.h"
#endif
#ifndef __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__
#include "sources/juce_MixerAudioSource.h"
#endif
#ifndef __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__
#include "sources/juce_PositionableAudioSource.h"
#endif
#ifndef __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__
#include "sources/juce_ResamplingAudioSource.h"
#endif
#ifndef __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__
#include "sources/juce_ReverbAudioSource.h"
#endif
#ifndef __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__
#include "sources/juce_ToneGeneratorAudioSource.h"
#endif
#ifndef __JUCE_SYNTHESISER_JUCEHEADER__
#include "synthesisers/juce_Synthesiser.h"
#endif
// END_AUTOINCLUDE

}

#endif // __JUCE_AUDIO_BASICS_JUCEHEADER__
@@ -0,0 +1,26 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/

#include "juce_audio_basics.cpp"
@@ -0,0 +1,21 @@
{
"id": "juce_audio_basics",
"name": "JUCE audio and midi data classes",
"version": "2.0.32",
"description": "Classes for audio buffer manipulation, midi message handling, synthesis, etc",
"website": "http://www.juce.com/juce",
"license": "GPL/Commercial",

"dependencies": [ { "id": "juce_core", "version": "matching" } ],

"include": "juce_audio_basics.h",

"compile": [ { "file": "juce_audio_basics.cpp", "target": "! xcode" },
{ "file": "juce_audio_basics.mm", "target": "xcode" } ],

"browse": [ "buffers/*",
"midi/*",
"effects/*",
"sources/*",
"synthesisers/*" ]
}
@@ -0,0 +1,290 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/

namespace MidiBufferHelpers
{
inline int getEventTime (const void* const d) noexcept
{
return *static_cast <const int*> (d);
}

inline uint16 getEventDataSize (const void* const d) noexcept
{
return *reinterpret_cast <const uint16*> (static_cast <const char*> (d) + sizeof (int));
}

inline uint16 getEventTotalSize (const void* const d) noexcept
{
return getEventDataSize (d) + sizeof (int) + sizeof (uint16);
}

static int findActualEventLength (const uint8* const data, const int maxBytes) noexcept
{
unsigned int byte = (unsigned int) *data;
int size = 0;

if (byte == 0xf0 || byte == 0xf7)
{
const uint8* d = data + 1;

while (d < data + maxBytes)
if (*d++ == 0xf7)
break;

size = (int) (d - data);
}
else if (byte == 0xff)
{
int n;
const int bytesLeft = MidiMessage::readVariableLengthVal (data + 1, n);
size = jmin (maxBytes, n + 2 + bytesLeft);
}
else if (byte >= 0x80)
{
size = jmin (maxBytes, MidiMessage::getMessageLengthFromFirstByte ((uint8) byte));
}

return size;
}
}

//==============================================================================
MidiBuffer::MidiBuffer() noexcept
: bytesUsed (0)
{
}

MidiBuffer::MidiBuffer (const MidiMessage& message) noexcept
: bytesUsed (0)
{
addEvent (message, 0);
}

MidiBuffer::MidiBuffer (const MidiBuffer& other) noexcept
: data (other.data),
bytesUsed (other.bytesUsed)
{
}

MidiBuffer& MidiBuffer::operator= (const MidiBuffer& other) noexcept
{
bytesUsed = other.bytesUsed;
data = other.data;

return *this;
}

void MidiBuffer::swapWith (MidiBuffer& other) noexcept
{
data.swapWith (other.data);
std::swap (bytesUsed, other.bytesUsed);
}

MidiBuffer::~MidiBuffer()
{
}

inline uint8* MidiBuffer::getData() const noexcept
{
return static_cast <uint8*> (data.getData());
}

void MidiBuffer::clear() noexcept
{
bytesUsed = 0;
}

void MidiBuffer::clear (const int startSample, const int numSamples)
{
uint8* const start = findEventAfter (getData(), startSample - 1);
uint8* const end = findEventAfter (start, startSample + numSamples - 1);

if (end > start)
{
const int bytesToMove = bytesUsed - (int) (end - getData());

if (bytesToMove > 0)
memmove (start, end, (size_t) bytesToMove);

bytesUsed -= (int) (end - start);
}
}

void MidiBuffer::addEvent (const MidiMessage& m, const int sampleNumber)
{
addEvent (m.getRawData(), m.getRawDataSize(), sampleNumber);
}

void MidiBuffer::addEvent (const void* const newData, const int maxBytes, const int sampleNumber)
{
const int numBytes = MidiBufferHelpers::findActualEventLength (static_cast <const uint8*> (newData), maxBytes);

if (numBytes > 0)
{
size_t spaceNeeded = (size_t) bytesUsed + (size_t) numBytes + sizeof (int) + sizeof (uint16);
data.ensureSize ((spaceNeeded + spaceNeeded / 2 + 8) & ~(size_t) 7);

uint8* d = findEventAfter (getData(), sampleNumber);
const int bytesToMove = bytesUsed - (int) (d - getData());

if (bytesToMove > 0)
memmove (d + numBytes + sizeof (int) + sizeof (uint16), d, (size_t) bytesToMove);

*reinterpret_cast <int*> (d) = sampleNumber;
d += sizeof (int);
*reinterpret_cast <uint16*> (d) = (uint16) numBytes;
d += sizeof (uint16);

memcpy (d, newData, (size_t) numBytes);

bytesUsed += sizeof (int) + sizeof (uint16) + (size_t) numBytes;
}
}

void MidiBuffer::addEvents (const MidiBuffer& otherBuffer,
const int startSample,
const int numSamples,
const int sampleDeltaToAdd)
{
Iterator i (otherBuffer);
i.setNextSamplePosition (startSample);

const uint8* eventData;
int eventSize, position;

while (i.getNextEvent (eventData, eventSize, position)
&& (position < startSample + numSamples || numSamples < 0))
{
addEvent (eventData, eventSize, position + sampleDeltaToAdd);
}
}

void MidiBuffer::ensureSize (size_t minimumNumBytes)
{
data.ensureSize (minimumNumBytes);
}

bool MidiBuffer::isEmpty() const noexcept
{
return bytesUsed == 0;
}

int MidiBuffer::getNumEvents() const noexcept
{
int n = 0;
const uint8* d = getData();
const uint8* const end = d + bytesUsed;

while (d < end)
{
d += MidiBufferHelpers::getEventTotalSize (d);
++n;
}

return n;
}

int MidiBuffer::getFirstEventTime() const noexcept
{
return bytesUsed > 0 ? MidiBufferHelpers::getEventTime (data.getData()) : 0;
}

int MidiBuffer::getLastEventTime() const noexcept
{
if (bytesUsed == 0)
return 0;

const uint8* d = getData();
const uint8* const endData = d + bytesUsed;

for (;;)
{
const uint8* const nextOne = d + MidiBufferHelpers::getEventTotalSize (d);

if (nextOne >= endData)
return MidiBufferHelpers::getEventTime (d);

d = nextOne;
}
}

uint8* MidiBuffer::findEventAfter (uint8* d, const int samplePosition) const noexcept
{
const uint8* const endData = getData() + bytesUsed;

while (d < endData && MidiBufferHelpers::getEventTime (d) <= samplePosition)
d += MidiBufferHelpers::getEventTotalSize (d);

return d;
}

//==============================================================================
MidiBuffer::Iterator::Iterator (const MidiBuffer& buffer_) noexcept
: buffer (buffer_),
data (buffer_.getData())
{
}

MidiBuffer::Iterator::~Iterator() noexcept
{
}

//==============================================================================
void MidiBuffer::Iterator::setNextSamplePosition (const int samplePosition) noexcept
{
data = buffer.getData();
const uint8* dataEnd = data + buffer.bytesUsed;

while (data < dataEnd && MidiBufferHelpers::getEventTime (data) < samplePosition)
data += MidiBufferHelpers::getEventTotalSize (data);
}

bool MidiBuffer::Iterator::getNextEvent (const uint8* &midiData, int& numBytes, int& samplePosition) noexcept
{
if (data >= buffer.getData() + buffer.bytesUsed)
return false;

samplePosition = MidiBufferHelpers::getEventTime (data);
numBytes = MidiBufferHelpers::getEventDataSize (data);
data += sizeof (int) + sizeof (uint16);
midiData = data;
data += numBytes;

return true;
}

bool MidiBuffer::Iterator::getNextEvent (MidiMessage& result, int& samplePosition) noexcept
{
if (data >= buffer.getData() + buffer.bytesUsed)
return false;

samplePosition = MidiBufferHelpers::getEventTime (data);
const int numBytes = MidiBufferHelpers::getEventDataSize (data);
data += sizeof (int) + sizeof (uint16);
result = MidiMessage (data, numBytes, samplePosition);
data += numBytes;

return true;
}
@@ -0,0 +1,241 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/

#ifndef __JUCE_MIDIBUFFER_JUCEHEADER__
#define __JUCE_MIDIBUFFER_JUCEHEADER__

#include "juce_MidiMessage.h"


//==============================================================================
/**
Holds a sequence of time-stamped midi events.
Analogous to the AudioSampleBuffer, this holds a set of midi events with
integer time-stamps. The buffer is kept sorted in order of the time-stamps.
If you're working with a sequence of midi events that may need to be manipulated
or read/written to a midi file, then MidiMessageSequence is probably a more
appropriate container. MidiBuffer is designed for lower-level streams of raw
midi data.
@see MidiMessage
*/
class JUCE_API MidiBuffer
{
public:
//==============================================================================
/** Creates an empty MidiBuffer. */
MidiBuffer() noexcept;

/** Creates a MidiBuffer containing a single midi message. */
explicit MidiBuffer (const MidiMessage& message) noexcept;

/** Creates a copy of another MidiBuffer. */
MidiBuffer (const MidiBuffer& other) noexcept;

/** Makes a copy of another MidiBuffer. */
MidiBuffer& operator= (const MidiBuffer& other) noexcept;

/** Destructor */
~MidiBuffer();

//==============================================================================
/** Removes all events from the buffer. */
void clear() noexcept;

/** Removes all events between two times from the buffer.
All events for which (start <= event position < start + numSamples) will
be removed.
*/
void clear (int start, int numSamples);

/** Returns true if the buffer is empty.
To actually retrieve the events, use a MidiBuffer::Iterator object
*/
bool isEmpty() const noexcept;

/** Counts the number of events in the buffer.
This is actually quite a slow operation, as it has to iterate through all
the events, so you might prefer to call isEmpty() if that's all you need
to know.
*/
int getNumEvents() const noexcept;

/** Adds an event to the buffer.
The sample number will be used to determine the position of the event in
the buffer, which is always kept sorted. The MidiMessage's timestamp is
ignored.
If an event is added whose sample position is the same as one or more events
already in the buffer, the new event will be placed after the existing ones.
To retrieve events, use a MidiBuffer::Iterator object
*/
void addEvent (const MidiMessage& midiMessage, int sampleNumber);

/** Adds an event to the buffer from raw midi data.
The sample number will be used to determine the position of the event in
the buffer, which is always kept sorted.
If an event is added whose sample position is the same as one or more events
already in the buffer, the new event will be placed after the existing ones.
The event data will be inspected to calculate the number of bytes in length that
the midi event really takes up, so maxBytesOfMidiData may be longer than the data
that actually gets stored. E.g. if you pass in a note-on and a length of 4 bytes,
it'll actually only store 3 bytes. If the midi data is invalid, it might not
add an event at all.
To retrieve events, use a MidiBuffer::Iterator object
*/
void addEvent (const void* rawMidiData,
int maxBytesOfMidiData,
int sampleNumber);

/** Adds some events from another buffer to this one.
@param otherBuffer the buffer containing the events you want to add
@param startSample the lowest sample number in the source buffer for which
events should be added. Any source events whose timestamp is
less than this will be ignored
@param numSamples the valid range of samples from the source buffer for which
events should be added - i.e. events in the source buffer whose
timestamp is greater than or equal to (startSample + numSamples)
will be ignored. If this value is less than 0, all events after
startSample will be taken.
@param sampleDeltaToAdd a value which will be added to the source timestamps of the events
that are added to this buffer
*/
void addEvents (const MidiBuffer& otherBuffer,
int startSample,
int numSamples,
int sampleDeltaToAdd);

/** Returns the sample number of the first event in the buffer.
If the buffer's empty, this will just return 0.
*/
int getFirstEventTime() const noexcept;

/** Returns the sample number of the last event in the buffer.
If the buffer's empty, this will just return 0.
*/
int getLastEventTime() const noexcept;

//==============================================================================
/** Exchanges the contents of this buffer with another one.
This is a quick operation, because no memory allocating or copying is done, it
just swaps the internal state of the two buffers.
*/
void swapWith (MidiBuffer& other) noexcept;

/** Preallocates some memory for the buffer to use.
This helps to avoid needing to reallocate space when the buffer has messages
added to it.
*/
void ensureSize (size_t minimumNumBytes);

//==============================================================================
/**
Used to iterate through the events in a MidiBuffer.
Note that altering the buffer while an iterator is using it isn't a
safe operation.
@see MidiBuffer
*/
class JUCE_API Iterator
{
public:
//==============================================================================
/** Creates an Iterator for this MidiBuffer. */
Iterator (const MidiBuffer& buffer) noexcept;

/** Destructor. */
~Iterator() noexcept;

//==============================================================================
/** Repositions the iterator so that the next event retrieved will be the first
one whose sample position is at greater than or equal to the given position.
*/
void setNextSamplePosition (int samplePosition) noexcept;

/** Retrieves a copy of the next event from the buffer.
@param result on return, this will be the message (the MidiMessage's timestamp
is not set)
@param samplePosition on return, this will be the position of the event
@returns true if an event was found, or false if the iterator has reached
the end of the buffer
*/
bool getNextEvent (MidiMessage& result,
int& samplePosition) noexcept;

/** Retrieves the next event from the buffer.
@param midiData on return, this pointer will be set to a block of data containing
the midi message. Note that to make it fast, this is a pointer
directly into the MidiBuffer's internal data, so is only valid
temporarily until the MidiBuffer is altered.
@param numBytesOfMidiData on return, this is the number of bytes of data used by the
midi message
@param samplePosition on return, this will be the position of the event
@returns true if an event was found, or false if the iterator has reached
the end of the buffer
*/
bool getNextEvent (const uint8* &midiData,
int& numBytesOfMidiData,
int& samplePosition) noexcept;

private:
//==============================================================================
const MidiBuffer& buffer;
const uint8* data;

JUCE_DECLARE_NON_COPYABLE (Iterator)
};

private:
//==============================================================================
friend class MidiBuffer::Iterator;
MemoryBlock data;
int bytesUsed;

uint8* getData() const noexcept;
uint8* findEventAfter (uint8*, int samplePosition) const noexcept;

JUCE_LEAK_DETECTOR (MidiBuffer)
};


#endif // __JUCE_MIDIBUFFER_JUCEHEADER__

Large diffs are not rendered by default.

@@ -0,0 +1,187 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/

#ifndef __JUCE_MIDIFILE_JUCEHEADER__
#define __JUCE_MIDIFILE_JUCEHEADER__

#include "juce_MidiMessageSequence.h"


//==============================================================================
/**
Reads/writes standard midi format files.
To read a midi file, create a MidiFile object and call its readFrom() method. You
can then get the individual midi tracks from it using the getTrack() method.
To write a file, create a MidiFile object, add some MidiMessageSequence objects
to it using the addTrack() method, and then call its writeTo() method to stream
it out.
@see MidiMessageSequence
*/
class JUCE_API MidiFile
{
public:
//==============================================================================
/** Creates an empty MidiFile object.
*/
MidiFile();

/** Destructor. */
~MidiFile();

//==============================================================================
/** Returns the number of tracks in the file.
@see getTrack, addTrack
*/
int getNumTracks() const noexcept;

/** Returns a pointer to one of the tracks in the file.
@returns a pointer to the track, or nullptr if the index is out-of-range
@see getNumTracks, addTrack
*/
const MidiMessageSequence* getTrack (int index) const noexcept;

/** Adds a midi track to the file.
This will make its own internal copy of the sequence that is passed-in.
@see getNumTracks, getTrack
*/
void addTrack (const MidiMessageSequence& trackSequence);

/** Removes all midi tracks from the file.
@see getNumTracks
*/
void clear();

/** Returns the raw time format code that will be written to a stream.
After reading a midi file, this method will return the time-format that
was read from the file's header. It can be changed using the setTicksPerQuarterNote()
or setSmpteTimeFormat() methods.
If the value returned is positive, it indicates the number of midi ticks
per quarter-note - see setTicksPerQuarterNote().
It it's negative, the upper byte indicates the frames-per-second (but negative), and
the lower byte is the number of ticks per frame - see setSmpteTimeFormat().
*/
short getTimeFormat() const noexcept;

/** Sets the time format to use when this file is written to a stream.
If this is called, the file will be written as bars/beats using the
specified resolution, rather than SMPTE absolute times, as would be
used if setSmpteTimeFormat() had been called instead.
@param ticksPerQuarterNote e.g. 96, 960
@see setSmpteTimeFormat
*/
void setTicksPerQuarterNote (int ticksPerQuarterNote) noexcept;

/** Sets the time format to use when this file is written to a stream.
If this is called, the file will be written using absolute times, rather
than bars/beats as would be the case if setTicksPerBeat() had been called
instead.
@param framesPerSecond must be 24, 25, 29 or 30
@param subframeResolution the sub-second resolution, e.g. 4 (midi time code),
8, 10, 80 (SMPTE bit resolution), or 100. For millisecond
timing, setSmpteTimeFormat (25, 40)
@see setTicksPerBeat
*/
void setSmpteTimeFormat (int framesPerSecond,
int subframeResolution) noexcept;

//==============================================================================
/** Makes a list of all the tempo-change meta-events from all tracks in the midi file.
Useful for finding the positions of all the tempo changes in a file.
@param tempoChangeEvents a list to which all the events will be added
*/
void findAllTempoEvents (MidiMessageSequence& tempoChangeEvents) const;

/** Makes a list of all the time-signature meta-events from all tracks in the midi file.
Useful for finding the positions of all the tempo changes in a file.
@param timeSigEvents a list to which all the events will be added
*/
void findAllTimeSigEvents (MidiMessageSequence& timeSigEvents) const;

/** Returns the latest timestamp in any of the tracks.
(Useful for finding the length of the file).
*/
double getLastTimestamp() const;

//==============================================================================
/** Reads a midi file format stream.
After calling this, you can get the tracks that were read from the file by using the
getNumTracks() and getTrack() methods.
The timestamps of the midi events in the tracks will represent their positions in
terms of midi ticks. To convert them to seconds, use the convertTimestampTicksToSeconds()
method.
@returns true if the stream was read successfully
*/
bool readFrom (InputStream& sourceStream);

/** Writes the midi tracks as a standard midi file.
@returns true if the operation succeeded.
*/
bool writeTo (OutputStream& destStream);

/** Converts the timestamp of all the midi events from midi ticks to seconds.
This will use the midi time format and tempo/time signature info in the
tracks to convert all the timestamps to absolute values in seconds.
*/
void convertTimestampTicksToSeconds();


private:
//==============================================================================
OwnedArray <MidiMessageSequence> tracks;
short timeFormat;

void readNextTrack (const uint8* data, int size);
void writeTrack (OutputStream& mainOut, int trackNum);

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiFile)
};


#endif // __JUCE_MIDIFILE_JUCEHEADER__
@@ -0,0 +1,184 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/

MidiKeyboardState::MidiKeyboardState()
{
zerostruct (noteStates);
}

MidiKeyboardState::~MidiKeyboardState()
{
}

//==============================================================================
void MidiKeyboardState::reset()
{
const ScopedLock sl (lock);
zerostruct (noteStates);
eventsToAdd.clear();
}

bool MidiKeyboardState::isNoteOn (const int midiChannel, const int n) const noexcept
{
jassert (midiChannel >= 0 && midiChannel <= 16);

return isPositiveAndBelow (n, (int) 128)
&& (noteStates[n] & (1 << (midiChannel - 1))) != 0;
}

bool MidiKeyboardState::isNoteOnForChannels (const int midiChannelMask, const int n) const noexcept
{
return isPositiveAndBelow (n, (int) 128)
&& (noteStates[n] & midiChannelMask) != 0;
}

void MidiKeyboardState::noteOn (const int midiChannel, const int midiNoteNumber, const float velocity)
{
jassert (midiChannel >= 0 && midiChannel <= 16);
jassert (isPositiveAndBelow (midiNoteNumber, (int) 128));

const ScopedLock sl (lock);

if (isPositiveAndBelow (midiNoteNumber, (int) 128))
{
const int timeNow = (int) Time::getMillisecondCounter();
eventsToAdd.addEvent (MidiMessage::noteOn (midiChannel, midiNoteNumber, velocity), timeNow);
eventsToAdd.clear (0, timeNow - 500);

noteOnInternal (midiChannel, midiNoteNumber, velocity);
}
}

void MidiKeyboardState::noteOnInternal (const int midiChannel, const int midiNoteNumber, const float velocity)
{
if (isPositiveAndBelow (midiNoteNumber, (int) 128))
{
noteStates [midiNoteNumber] |= (1 << (midiChannel - 1));

for (int i = listeners.size(); --i >= 0;)
listeners.getUnchecked(i)->handleNoteOn (this, midiChannel, midiNoteNumber, velocity);
}
}

void MidiKeyboardState::noteOff (const int midiChannel, const int midiNoteNumber)
{
const ScopedLock sl (lock);

if (isNoteOn (midiChannel, midiNoteNumber))
{
const int timeNow = (int) Time::getMillisecondCounter();
eventsToAdd.addEvent (MidiMessage::noteOff (midiChannel, midiNoteNumber), timeNow);
eventsToAdd.clear (0, timeNow - 500);

noteOffInternal (midiChannel, midiNoteNumber);
}
}

void MidiKeyboardState::noteOffInternal (const int midiChannel, const int midiNoteNumber)
{
if (isNoteOn (midiChannel, midiNoteNumber))
{
noteStates [midiNoteNumber] &= ~(1 << (midiChannel - 1));

for (int i = listeners.size(); --i >= 0;)
listeners.getUnchecked(i)->handleNoteOff (this, midiChannel, midiNoteNumber);
}
}

void MidiKeyboardState::allNotesOff (const int midiChannel)
{
const ScopedLock sl (lock);

if (midiChannel <= 0)
{
for (int i = 1; i <= 16; ++i)
allNotesOff (i);
}
else
{
for (int i = 0; i < 128; ++i)
noteOff (midiChannel, i);
}
}

void MidiKeyboardState::processNextMidiEvent (const MidiMessage& message)
{
if (message.isNoteOn())
{
noteOnInternal (message.getChannel(), message.getNoteNumber(), message.getFloatVelocity());
}
else if (message.isNoteOff())
{
noteOffInternal (message.getChannel(), message.getNoteNumber());
}
else if (message.isAllNotesOff())
{
for (int i = 0; i < 128; ++i)
noteOffInternal (message.getChannel(), i);
}
}

void MidiKeyboardState::processNextMidiBuffer (MidiBuffer& buffer,
const int startSample,
const int numSamples,
const bool injectIndirectEvents)
{
MidiBuffer::Iterator i (buffer);
MidiMessage message (0xf4, 0.0);
int time;

const ScopedLock sl (lock);

while (i.getNextEvent (message, time))
processNextMidiEvent (message);

if (injectIndirectEvents)
{
MidiBuffer::Iterator i2 (eventsToAdd);
const int firstEventToAdd = eventsToAdd.getFirstEventTime();
const double scaleFactor = numSamples / (double) (eventsToAdd.getLastEventTime() + 1 - firstEventToAdd);

while (i2.getNextEvent (message, time))
{
const int pos = jlimit (0, numSamples - 1, roundToInt ((time - firstEventToAdd) * scaleFactor));
buffer.addEvent (message, startSample + pos);
}
}

eventsToAdd.clear();
}

//==============================================================================
void MidiKeyboardState::addListener (MidiKeyboardStateListener* const listener)
{
const ScopedLock sl (lock);
listeners.addIfNotAlreadyThere (listener);
}

void MidiKeyboardState::removeListener (MidiKeyboardStateListener* const listener)
{
const ScopedLock sl (lock);
listeners.removeFirstMatchingValue (listener);
}
@@ -0,0 +1,209 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/

#ifndef __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__
#define __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__

#include "juce_MidiBuffer.h"
class MidiKeyboardState;


//==============================================================================
/**
Receives events from a MidiKeyboardState object.
@see MidiKeyboardState
*/
class JUCE_API MidiKeyboardStateListener
{
public:
//==============================================================================
MidiKeyboardStateListener() noexcept {}
virtual ~MidiKeyboardStateListener() {}

//==============================================================================
/** Called when one of the MidiKeyboardState's keys is pressed.
This will be called synchronously when the state is either processing a
buffer in its MidiKeyboardState::processNextMidiBuffer() method, or
when a note is being played with its MidiKeyboardState::noteOn() method.
Note that this callback could happen from an audio callback thread, so be
careful not to block, and avoid any UI activity in the callback.
*/
virtual void handleNoteOn (MidiKeyboardState* source,
int midiChannel, int midiNoteNumber, float velocity) = 0;

/** Called when one of the MidiKeyboardState's keys is released.
This will be called synchronously when the state is either processing a
buffer in its MidiKeyboardState::processNextMidiBuffer() method, or
when a note is being played with its MidiKeyboardState::noteOff() method.
Note that this callback could happen from an audio callback thread, so be
careful not to block, and avoid any UI activity in the callback.
*/
virtual void handleNoteOff (MidiKeyboardState* source,
int midiChannel, int midiNoteNumber) = 0;
};


//==============================================================================
/**
Represents a piano keyboard, keeping track of which keys are currently pressed.
This object can parse a stream of midi events, using them to update its idea
of which keys are pressed for each individiual midi channel.
When keys go up or down, it can broadcast these events to listener objects.
It also allows key up/down events to be triggered with its noteOn() and noteOff()
methods, and midi messages for these events will be merged into the
midi stream that gets processed by processNextMidiBuffer().
*/
class JUCE_API MidiKeyboardState
{
public:
//==============================================================================
MidiKeyboardState();
~MidiKeyboardState();

//==============================================================================
/** Resets the state of the object.
All internal data for all the channels is reset, but no events are sent as a
result.
If you want to release any keys that are currently down, and to send out note-up
midi messages for this, use the allNotesOff() method instead.
*/
void reset();

/** Returns true if the given midi key is currently held down for the given midi channel.
The channel number must be between 1 and 16. If you want to see if any notes are
on for a range of channels, use the isNoteOnForChannels() method.
*/
bool isNoteOn (int midiChannel, int midiNoteNumber) const noexcept;

/** Returns true if the given midi key is currently held down on any of a set of midi channels.
The channel mask has a bit set for each midi channel you want to test for - bit
0 = midi channel 1, bit 1 = midi channel 2, etc.
If a note is on for at least one of the specified channels, this returns true.
*/
bool isNoteOnForChannels (int midiChannelMask, int midiNoteNumber) const noexcept;

/** Turns a specified note on.
This will cause a suitable midi note-on event to be injected into the midi buffer during the
next call to processNextMidiBuffer().
It will also trigger a synchronous callback to the listeners to tell them that the key has
gone down.
*/
void noteOn (int midiChannel, int midiNoteNumber, float velocity);

/** Turns a specified note off.
This will cause a suitable midi note-off event to be injected into the midi buffer during the
next call to processNextMidiBuffer().
It will also trigger a synchronous callback to the listeners to tell them that the key has
gone up.
But if the note isn't acutally down for the given channel, this method will in fact do nothing.
*/
void noteOff (int midiChannel, int midiNoteNumber);

/** This will turn off any currently-down notes for the given midi channel.
If you pass 0 for the midi channel, it will in fact turn off all notes on all channels.
Calling this method will make calls to noteOff(), so can trigger synchronous callbacks
and events being added to the midi stream.
*/
void allNotesOff (int midiChannel);

//==============================================================================
/** Looks at a key-up/down event and uses it to update the state of this object.
To process a buffer full of midi messages, use the processNextMidiBuffer() method
instead.
*/
void processNextMidiEvent (const MidiMessage& message);

/** Scans a midi stream for up/down events and adds its own events to it.
This will look for any up/down events and use them to update the internal state,
synchronously making suitable callbacks to the listeners.
If injectIndirectEvents is true, then midi events to produce the recent noteOn()
and noteOff() calls will be added into the buffer.
Only the section of the buffer whose timestamps are between startSample and
(startSample + numSamples) will be affected, and any events added will be placed
between these times.
If you're going to use this method, you'll need to keep calling it regularly for
it to work satisfactorily.
To process a single midi event at a time, use the processNextMidiEvent() method
instead.
*/
void processNextMidiBuffer (MidiBuffer& buffer,
int startSample,
int numSamples,
bool injectIndirectEvents);

//==============================================================================
/** Registers a listener for callbacks when keys go up or down.
@see removeListener
*/
void addListener (MidiKeyboardStateListener* listener);

/** Deregisters a listener.
@see addListener
*/
void removeListener (MidiKeyboardStateListener* listener);

private:
//==============================================================================
CriticalSection lock;
uint16 noteStates [128];
MidiBuffer eventsToAdd;
Array <MidiKeyboardStateListener*> listeners;

void noteOnInternal (int midiChannel, int midiNoteNumber, float velocity);
void noteOffInternal (int midiChannel, int midiNoteNumber);

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiKeyboardState)
};


#endif // __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -0,0 +1,335 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/

MidiMessageSequence::MidiMessageSequence()
{
}

MidiMessageSequence::MidiMessageSequence (const MidiMessageSequence& other)
{
list.ensureStorageAllocated (other.list.size());

for (int i = 0; i < other.list.size(); ++i)
list.add (new MidiEventHolder (other.list.getUnchecked(i)->message));
}

MidiMessageSequence& MidiMessageSequence::operator= (const MidiMessageSequence& other)
{
MidiMessageSequence otherCopy (other);
swapWith (otherCopy);
return *this;
}

void MidiMessageSequence::swapWith (MidiMessageSequence& other) noexcept
{
list.swapWithArray (other.list);
}

MidiMessageSequence::~MidiMessageSequence()
{
}

void MidiMessageSequence::clear()
{
list.clear();
}

int MidiMessageSequence::getNumEvents() const
{
return list.size();
}

MidiMessageSequence::MidiEventHolder* MidiMessageSequence::getEventPointer (const int index) const
{
return list [index];
}

double MidiMessageSequence::getTimeOfMatchingKeyUp (const int index) const
{
if (const MidiEventHolder* const meh = list [index])
if (meh->noteOffObject != nullptr)
return meh->noteOffObject->message.getTimeStamp();

return 0.0;
}

int MidiMessageSequence::getIndexOfMatchingKeyUp (const int index) const
{
if (const MidiEventHolder* const meh = list [index])
return list.indexOf (meh->noteOffObject);

return -1;
}

int MidiMessageSequence::getIndexOf (MidiEventHolder* const event) const
{
return list.indexOf (event);
}

int MidiMessageSequence::getNextIndexAtTime (const double timeStamp) const
{
const int numEvents = list.size();

int i;
for (i = 0; i < numEvents; ++i)
if (list.getUnchecked(i)->message.getTimeStamp() >= timeStamp)
break;

return i;
}

//==============================================================================
double MidiMessageSequence::getStartTime() const
{
return getEventTime (0);
}

double MidiMessageSequence::getEndTime() const
{
return getEventTime (list.size() - 1);
}

double MidiMessageSequence::getEventTime (const int index) const
{
if (const MidiEventHolder* const meh = list [index])
return meh->message.getTimeStamp();

return 0.0;
}

//==============================================================================
MidiMessageSequence::MidiEventHolder* MidiMessageSequence::addEvent (const MidiMessage& newMessage,
double timeAdjustment)
{
MidiEventHolder* const newOne = new MidiEventHolder (newMessage);

timeAdjustment += newMessage.getTimeStamp();
newOne->message.setTimeStamp (timeAdjustment);

int i;
for (i = list.size(); --i >= 0;)
if (list.getUnchecked(i)->message.getTimeStamp() <= timeAdjustment)
break;

list.insert (i + 1, newOne);
return newOne;
}

void MidiMessageSequence::deleteEvent (const int index,
const bool deleteMatchingNoteUp)
{
if (isPositiveAndBelow (index, list.size()))
{
if (deleteMatchingNoteUp)
deleteEvent (getIndexOfMatchingKeyUp (index), false);

list.remove (index);
}
}

struct MidiMessageSequenceSorter
{
static int compareElements (const MidiMessageSequence::MidiEventHolder* const first,
const MidiMessageSequence::MidiEventHolder* const second) noexcept
{
const double diff = first->message.getTimeStamp() - second->message.getTimeStamp();
return (diff > 0) - (diff < 0);
}
};

void MidiMessageSequence::addSequence (const MidiMessageSequence& other,
double timeAdjustment,
double firstAllowableTime,
double endOfAllowableDestTimes)
{
firstAllowableTime -= timeAdjustment;
endOfAllowableDestTimes -= timeAdjustment;

for (int i = 0; i < other.list.size(); ++i)
{
const MidiMessage& m = other.list.getUnchecked(i)->message;
const double t = m.getTimeStamp();

if (t >= firstAllowableTime && t < endOfAllowableDestTimes)
{
MidiEventHolder* const newOne = new MidiEventHolder (m);
newOne->message.setTimeStamp (timeAdjustment + t);

list.add (newOne);
}
}

sort();
}

//==============================================================================
void MidiMessageSequence::sort()
{
MidiMessageSequenceSorter sorter;
list.sort (sorter, true);
}

void MidiMessageSequence::updateMatchedPairs()
{
for (int i = 0; i < list.size(); ++i)
{
MidiEventHolder* const meh = list.getUnchecked(i);
const MidiMessage& m1 = meh->message;

if (m1.isNoteOn())
{
meh->noteOffObject = nullptr;
const int note = m1.getNoteNumber();
const int chan = m1.getChannel();
const int len = list.size();

for (int j = i + 1; j < len; ++j)
{
const MidiMessage& m = list.getUnchecked(j)->message;

if (m.getNoteNumber() == note && m.getChannel() == chan)
{
if (m.isNoteOff())
{
meh->noteOffObject = list[j];
break;
}
else if (m.isNoteOn())
{
MidiEventHolder* const newEvent = new MidiEventHolder (MidiMessage::noteOff (chan, note));
list.insert (j, newEvent);
newEvent->message.setTimeStamp (m.getTimeStamp());
meh->noteOffObject = newEvent;
break;
}
}
}
}
}
}

void MidiMessageSequence::addTimeToMessages (const double delta)
{
for (int i = list.size(); --i >= 0;)
{
MidiMessage& mm = list.getUnchecked(i)->message;
mm.setTimeStamp (mm.getTimeStamp() + delta);
}
}

//==============================================================================
void MidiMessageSequence::extractMidiChannelMessages (const int channelNumberToExtract,
MidiMessageSequence& destSequence,
const bool alsoIncludeMetaEvents) const
{
for (int i = 0; i < list.size(); ++i)
{
const MidiMessage& mm = list.getUnchecked(i)->message;

if (mm.isForChannel (channelNumberToExtract) || (alsoIncludeMetaEvents && mm.isMetaEvent()))
destSequence.addEvent (mm);
}
}

void MidiMessageSequence::extractSysExMessages (MidiMessageSequence& destSequence) const
{
for (int i = 0; i < list.size(); ++i)
{
const MidiMessage& mm = list.getUnchecked(i)->message;

if (mm.isSysEx())
destSequence.addEvent (mm);
}
}

void MidiMessageSequence::deleteMidiChannelMessages (const int channelNumberToRemove)
{
for (int i = list.size(); --i >= 0;)
if (list.getUnchecked(i)->message.isForChannel (channelNumberToRemove))
list.remove(i);
}

void MidiMessageSequence::deleteSysExMessages()
{
for (int i = list.size(); --i >= 0;)
if (list.getUnchecked(i)->message.isSysEx())
list.remove(i);
}

//==============================================================================
void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumber,
const double time,
OwnedArray<MidiMessage>& dest)
{
bool doneProg = false;
bool donePitchWheel = false;
Array <int> doneControllers;
doneControllers.ensureStorageAllocated (32);

for (int i = list.size(); --i >= 0;)
{
const MidiMessage& mm = list.getUnchecked(i)->message;

if (mm.isForChannel (channelNumber) && mm.getTimeStamp() <= time)
{
if (mm.isProgramChange())
{
if (! doneProg)
{
dest.add (new MidiMessage (mm, 0.0));
doneProg = true;
}
}
else if (mm.isController())
{
if (! doneControllers.contains (mm.getControllerNumber()))
{
dest.add (new MidiMessage (mm, 0.0));
doneControllers.add (mm.getControllerNumber());
}
}
else if (mm.isPitchWheel())
{
if (! donePitchWheel)
{
dest.add (new MidiMessage (mm, 0.0));
donePitchWheel = true;
}
}
}
}
}


//==============================================================================
MidiMessageSequence::MidiEventHolder::MidiEventHolder (const MidiMessage& mm)
: message (mm),
noteOffObject (nullptr)
{
}

MidiMessageSequence::MidiEventHolder::~MidiEventHolder()
{
}