further development

git-svn-id: http://moon:8086/svn/software/trunk/projects/RBM@17 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
2014-10-04 19:09:35 +00:00
parent b403b9776a
commit f62f1283f8
127 changed files with 2350 additions and 1235 deletions
@@ -165,13 +165,13 @@ bool LAMEEncoderAudioFormat::canHandleFile (const File&)
Array<int> LAMEEncoderAudioFormat::getPossibleSampleRates()
{
const int rates[] = { 32000, 44100, 48000, 0 };
return Array <int> (rates);
return Array<int> (rates);
}
Array<int> LAMEEncoderAudioFormat::getPossibleBitDepths()
{
const int depths[] = { 16, 0 };
return Array <int> (depths);
return Array<int> (depths);
}
bool LAMEEncoderAudioFormat::canDoStereo() { return true; }
@@ -65,6 +65,7 @@ const char* const WavAudioFormat::acidNumerator = "acid numerator";
const char* const WavAudioFormat::acidTempo = "acid tempo";
const char* const WavAudioFormat::ISRC = "ISRC";
const char* const WavAudioFormat::tracktionLoopInfo = "tracktion loop info";
//==============================================================================
namespace WavFileHelpers
@@ -481,6 +482,38 @@ namespace WavFileHelpers
input.read (this, (int) jmin (sizeof (*this), length));
}
AcidChunk (const StringPairArray& values)
{
zerostruct (*this);
flags = getFlagIfPresent (values, WavAudioFormat::acidOneShot, 0x01)
| getFlagIfPresent (values, WavAudioFormat::acidRootSet, 0x02)
| getFlagIfPresent (values, WavAudioFormat::acidStretch, 0x04)
| getFlagIfPresent (values, WavAudioFormat::acidDiskBased, 0x08)
| getFlagIfPresent (values, WavAudioFormat::acidizerFlag, 0x10);
if (values[WavAudioFormat::acidRootSet].getIntValue() != 0)
rootNote = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidRootNote].getIntValue());
numBeats = ByteOrder::swapIfBigEndian ((uint32) values[WavAudioFormat::acidBeats].getIntValue());
meterDenominator = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidDenominator].getIntValue());
meterNumerator = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidNumerator].getIntValue());
if (values.containsKey (WavAudioFormat::acidTempo))
tempo = swapFloatByteOrder (values[WavAudioFormat::acidTempo].getFloatValue());
}
static MemoryBlock createFrom (const StringPairArray& values)
{
return AcidChunk (values).toMemoryBlock();
}
MemoryBlock toMemoryBlock() const
{
return (flags != 0 || rootNote != 0 || numBeats != 0 || meterDenominator != 0 || meterNumerator != 0)
? MemoryBlock (this, sizeof (*this)) : MemoryBlock();
}
void addToMetadata (StringPairArray& values) const
{
setBoolFlag (values, WavAudioFormat::acidOneShot, 0x01);
@@ -490,30 +523,65 @@ namespace WavFileHelpers
setBoolFlag (values, WavAudioFormat::acidizerFlag, 0x10);
if (flags & 0x02) // root note set
values.set (WavAudioFormat::acidRootNote, String (rootNote));
values.set (WavAudioFormat::acidRootNote, String (ByteOrder::swapIfBigEndian (rootNote)));
values.set (WavAudioFormat::acidBeats, String (numBeats));
values.set (WavAudioFormat::acidDenominator, String (meterDenominator));
values.set (WavAudioFormat::acidNumerator, String (meterNumerator));
values.set (WavAudioFormat::acidTempo, String (tempo));
values.set (WavAudioFormat::acidBeats, String (ByteOrder::swapIfBigEndian (numBeats)));
values.set (WavAudioFormat::acidDenominator, String (ByteOrder::swapIfBigEndian (meterDenominator)));
values.set (WavAudioFormat::acidNumerator, String (ByteOrder::swapIfBigEndian (meterNumerator)));
values.set (WavAudioFormat::acidTempo, String (swapFloatByteOrder (tempo)));
}
void setBoolFlag (StringPairArray& values, const char* name, int32 mask) const
void setBoolFlag (StringPairArray& values, const char* name, uint32 mask) const
{
values.set (name, (flags & mask) ? "1" : "0");
values.set (name, (flags & ByteOrder::swapIfBigEndian (mask)) ? "1" : "0");
}
int32 flags;
int16 rootNote;
int16 reserved1;
static uint32 getFlagIfPresent (const StringPairArray& values, const char* name, uint32 flag)
{
return values[name].getIntValue() != 0 ? ByteOrder::swapIfBigEndian (flag) : 0;
}
static float swapFloatByteOrder (const float x) noexcept
{
#ifdef JUCE_BIG_ENDIAN
union { uint32 asInt; float asFloat; } n;
n.asFloat = x;
n.asInt = ByteOrder::swap (n.asInt);
return n.asFloat;
#else
return x;
#endif
}
uint32 flags;
uint16 rootNote;
uint16 reserved1;
float reserved2;
int32 numBeats;
int16 meterDenominator;
int16 meterNumerator;
uint32 numBeats;
uint16 meterDenominator;
uint16 meterNumerator;
float tempo;
} JUCE_PACKED;
//==============================================================================
struct TracktionChunk
{
static MemoryBlock createFrom (const StringPairArray& values)
{
const String s = values[WavAudioFormat::tracktionLoopInfo];
MemoryBlock data;
if (s.isNotEmpty())
{
MemoryOutputStream os (data, false);
os.writeString (s);
}
return data;
}
};
//==============================================================================
namespace AXMLChunk
{
@@ -816,6 +884,12 @@ public:
{
AcidChunk (*input, length).addToMetadata (metadataValues);
}
else if (chunkType == chunkName ("Trkn"))
{
MemoryBlock tracktion;
input->readIntoMemoryBlock (tracktion, (ssize_t) length);
metadataValues.set (WavAudioFormat::tracktionLoopInfo, tracktion.toString());
}
else if (chunkEnd <= input->getPosition())
{
break;
@@ -919,6 +993,8 @@ public:
instChunk = InstChunk::createFrom (metadataValues);
cueChunk = CueChunk ::createFrom (metadataValues);
listChunk = ListChunk::createFrom (metadataValues);
acidChunk = AcidChunk::createFrom (metadataValues);
trckChunk = TracktionChunk::createFrom (metadataValues);
}
headerPosition = out->getPosition();
@@ -981,7 +1057,7 @@ public:
}
private:
MemoryBlock tempBlock, bwavChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk;
MemoryBlock tempBlock, bwavChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk, acidChunk, trckChunk;
uint64 lengthInSamples, bytesWritten;
int64 headerPosition;
bool writeFailed;
@@ -1033,6 +1109,8 @@ private:
+ chunkSize (instChunk)
+ chunkSize (cueChunk)
+ chunkSize (listChunk)
+ chunkSize (acidChunk)
+ chunkSize (trckChunk)
+ (8 + 28)); // (ds64 chunk)
riffChunkSize += (riffChunkSize & 1);
@@ -1112,6 +1190,8 @@ private:
writeChunk (instChunk, chunkName ("inst"), 7);
writeChunk (cueChunk, chunkName ("cue "));
writeChunk (listChunk, chunkName ("LIST"));
writeChunk (acidChunk, chunkName ("acid"));
writeChunk (trckChunk, chunkName ("Trkn"));
writeChunkHeader (chunkName ("data"), isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame));
@@ -135,6 +135,9 @@ public:
/** Metadata property name used when reading an ISRC code from an AXML chunk. */
static const char* const ISRC;
/** Metadata property name used when reading a WAV file with a Tracktion chunk. */
static const char* const tracktionLoopInfo;
//==============================================================================
Array<int> getPossibleSampleRates() override;
Array<int> getPossibleBitDepths() override;
@@ -173,35 +173,54 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer,
}
}
template <typename SampleType>
static Range<SampleType> getChannelMinAndMax (SampleType* channel, int numSamples) noexcept
void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples,
Range<float>* const results, const int channelsToRead)
{
return Range<SampleType>::findMinAndMax (channel, numSamples);
}
jassert (channelsToRead > 0 && channelsToRead <= (int) numChannels);
static Range<float> getChannelMinAndMax (float* channel, int numSamples) noexcept
{
return FloatVectorOperations::findMinAndMax (channel, numSamples);
}
template <typename SampleType>
static void getStereoMinAndMax (SampleType* const* channels, const int numChannels, const int numSamples,
SampleType& lmin, SampleType& lmax, SampleType& rmin, SampleType& rmax)
{
Range<SampleType> range (getChannelMinAndMax (channels[0], numSamples));
lmax = jmax (lmax, range.getEnd());
lmin = jmin (lmin, range.getStart());
if (numChannels > 1)
if (numSamples <= 0)
{
range = getChannelMinAndMax (channels[1], numSamples);
rmax = jmax (rmax, range.getEnd());
rmin = jmin (rmin, range.getStart());
for (int i = 0; i < channelsToRead; ++i)
results[i] = Range<float>();
return;
}
else
const int bufferSize = (int) jmin (numSamples, (int64) 4096);
AudioSampleBuffer tempSampleBuffer ((int) channelsToRead, bufferSize);
float* const* const floatBuffer = tempSampleBuffer.getArrayOfWritePointers();
int* const* intBuffer = reinterpret_cast<int* const*> (floatBuffer);
bool isFirstBlock = true;
while (numSamples > 0)
{
rmax = lmax;
rmin = lmin;
const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
if (! read (intBuffer, channelsToRead, startSampleInFile, numToDo, false))
break;
for (int i = 0; i < channelsToRead; ++i)
{
Range<float> r;
if (usesFloatingPointData)
{
r = FloatVectorOperations::findMinAndMax (floatBuffer[i], numToDo);
}
else
{
Range<int> intRange (Range<int>::findMinAndMax (intBuffer[i], numToDo));
r = Range<float> (intRange.getStart() / (float) std::numeric_limits<int>::max(),
intRange.getEnd() / (float) std::numeric_limits<int>::max());
}
results[i] = isFirstBlock ? r : results[i].getUnionWith (r);
}
isFirstBlock = false;
numSamples -= numToDo;
startSampleInFile += numToDo;
}
}
@@ -209,66 +228,20 @@ void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples
float& lowestLeft, float& highestLeft,
float& lowestRight, float& highestRight)
{
if (numSamples <= 0)
Range<float> levels[2];
readMaxLevels (startSampleInFile, numSamples, levels, jmin (2, (int) numChannels));
lowestLeft = levels[0].getStart();
highestLeft = levels[0].getEnd();
if (numChannels > 1)
{
lowestLeft = 0;
lowestRight = 0;
highestLeft = 0;
highestRight = 0;
return;
}
const int bufferSize = (int) jmin (numSamples, (int64) 4096);
AudioSampleBuffer tempSampleBuffer ((int) numChannels, bufferSize);
float* const* const floatBuffer = tempSampleBuffer.getArrayOfWritePointers();
int* const* intBuffer = reinterpret_cast<int* const*> (floatBuffer);
if (usesFloatingPointData)
{
float lmin = 1.0e6f;
float lmax = -lmin;
float rmin = lmin;
float rmax = lmax;
while (numSamples > 0)
{
const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
if (! read (intBuffer, 2, startSampleInFile, numToDo, false))
break;
numSamples -= numToDo;
startSampleInFile += numToDo;
getStereoMinAndMax (floatBuffer, (int) numChannels, numToDo, lmin, lmax, rmin, rmax);
}
lowestLeft = lmin;
highestLeft = lmax;
lowestRight = rmin;
highestRight = rmax;
lowestRight = levels[1].getStart();
highestRight = levels[1].getEnd();
}
else
{
int lmax = std::numeric_limits<int>::min();
int lmin = std::numeric_limits<int>::max();
int rmax = std::numeric_limits<int>::min();
int rmin = std::numeric_limits<int>::max();
while (numSamples > 0)
{
const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
if (! read (intBuffer, 2, startSampleInFile, numToDo, false))
break;
numSamples -= numToDo;
startSampleInFile += numToDo;
getStereoMinAndMax (intBuffer, (int) numChannels, numToDo, lmin, lmax, rmin, rmax);
}
lowestLeft = lmin / (float) std::numeric_limits<int>::max();
highestLeft = lmax / (float) std::numeric_limits<int>::max();
lowestRight = rmin / (float) std::numeric_limits<int>::max();
highestRight = rmax / (float) std::numeric_limits<int>::max();
lowestRight = lowestLeft;
highestRight = highestLeft;
}
}
@@ -121,6 +121,25 @@ public:
bool useReaderLeftChan,
bool useReaderRightChan);
/** Finds the highest and lowest sample levels from a section of the audio stream.
This will read a block of samples from the stream, and measure the
highest and lowest sample levels from the channels in that section, returning
these as normalised floating-point levels.
@param startSample the offset into the audio stream to start reading from. It's
ok for this to be beyond the start or end of the stream.
@param numSamples how many samples to read
@param results this array will be filled with Range values for each channel.
The array must contain numChannels elements.
@param numChannelsToRead the number of channels of data to scan. This must be
more than zero, but not more than the total number of channels
that the reader contains
@see read
*/
virtual void readMaxLevels (int64 startSample, int64 numSamples,
Range<float>* results, int numChannelsToRead);
/** Finds the highest and lowest sample levels from a section of the audio stream.
This will read a block of samples from the stream, and measure the
@@ -138,12 +157,9 @@ public:
channel (if there is one)
@see read
*/
virtual void readMaxLevels (int64 startSample,
int64 numSamples,
float& lowestLeft,
float& highestLeft,
float& lowestRight,
float& highestRight);
virtual void readMaxLevels (int64 startSample, int64 numSamples,
float& lowestLeft, float& highestLeft,
float& lowestRight, float& highestRight);
/** Scans the source looking for a sample whose magnitude is in a specified range.
@@ -59,12 +59,12 @@ SamplerSound::~SamplerSound()
{
}
bool SamplerSound::appliesToNote (const int midiNoteNumber)
bool SamplerSound::appliesToNote (int midiNoteNumber)
{
return midiNotes [midiNoteNumber];
}
bool SamplerSound::appliesToChannel (const int /*midiChannel*/)
bool SamplerSound::appliesToChannel (int /*midiChannel*/)
{
return true;
}
@@ -127,7 +127,7 @@ void SamplerVoice::startNote (const int midiNoteNumber,
}
}
void SamplerVoice::stopNote (const bool allowTailOff)
void SamplerVoice::stopNote (float /*velocity*/, bool allowTailOff)
{
if (allowTailOff)
{
@@ -197,7 +197,7 @@ void SamplerVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSa
if (attackReleaseLevel <= 0.0f)
{
stopNote (false);
stopNote (0.0f, false);
break;
}
}
@@ -216,7 +216,7 @@ void SamplerVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSa
if (sourceSamplePosition > playingSound->length)
{
stopNote (false);
stopNote (0.0f, false);
break;
}
}
@@ -82,8 +82,8 @@ public:
//==============================================================================
bool appliesToNote (const int midiNoteNumber) override;
bool appliesToChannel (const int midiChannel) override;
bool appliesToNote (int midiNoteNumber) override;
bool appliesToChannel (int midiChannel) override;
private:
@@ -124,7 +124,7 @@ public:
bool canPlaySound (SynthesiserSound*) override;
void startNote (int midiNoteNumber, float velocity, SynthesiserSound*, int pitchWheel) override;
void stopNote (bool allowTailOff) override;
void stopNote (float velocity, bool allowTailOff) override;
void pitchWheelMoved (int newValue);
void controllerMoved (int controllerNumber, int newValue) override;