mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-14 00:14:18 +00:00
Added the AudioData class, which contains a range of templated structrures for manipulating different sample type primitives. This will replace the old AudioDataConverters class, and I've refactored a lot of the audio devices and formats to use the new classes.
This commit is contained in:
parent
8f4aaa4873
commit
ba62157841
27 changed files with 1603 additions and 2510 deletions
|
|
@ -36,7 +36,9 @@
|
|||
*/
|
||||
#include "JucePluginCharacteristics.h"
|
||||
|
||||
#define JUCE_SUPPORT_CARBON 1
|
||||
#if ! defined (__LP64__)
|
||||
#define JUCE_SUPPORT_CARBON 1
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// The following stuff is just to cause a compile error if you've forgotten to
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@
|
|||
|
||||
//[MiscUserDefs] You can add your own user definitions and misc code here...
|
||||
class DemoThumbnailComp : public Component,
|
||||
public ChangeListener
|
||||
public ChangeListener,
|
||||
public FileDragAndDropTarget
|
||||
{
|
||||
public:
|
||||
DemoThumbnailComp()
|
||||
|
|
@ -104,6 +105,19 @@ public:
|
|||
repaint();
|
||||
}
|
||||
|
||||
bool isInterestedInFileDrag (const StringArray& files)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void filesDropped (const StringArray& files, int x, int y)
|
||||
{
|
||||
AudioDemoPlaybackPage* demoPage = findParentComponentOfClass ((AudioDemoPlaybackPage*) 0);
|
||||
|
||||
if (demoPage != 0)
|
||||
demoPage->showFile (File (files[0]));
|
||||
}
|
||||
|
||||
AudioFormatManager formatManager;
|
||||
AudioThumbnailCache thumbnailCache;
|
||||
AudioThumbnail thumbnail;
|
||||
|
|
@ -266,6 +280,14 @@ void AudioDemoPlaybackPage::sliderValueChanged (Slider* sliderThatWasMoved)
|
|||
|
||||
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
|
||||
|
||||
void AudioDemoPlaybackPage::showFile (const File& file)
|
||||
{
|
||||
loadFileIntoTransport (file);
|
||||
|
||||
zoomSlider->setValue (0, false, false);
|
||||
thumbnail->setFile (file);
|
||||
}
|
||||
|
||||
void AudioDemoPlaybackPage::loadFileIntoTransport (const File& audioFile)
|
||||
{
|
||||
// unload the previous file source and delete it..
|
||||
|
|
@ -292,10 +314,7 @@ void AudioDemoPlaybackPage::loadFileIntoTransport (const File& audioFile)
|
|||
|
||||
void AudioDemoPlaybackPage::selectionChanged()
|
||||
{
|
||||
loadFileIntoTransport (fileTreeComp->getSelectedFile());
|
||||
|
||||
zoomSlider->setValue (0, false, false);
|
||||
thumbnail->setFile (fileTreeComp->getSelectedFile());
|
||||
showFile (fileTreeComp->getSelectedFile());
|
||||
}
|
||||
|
||||
void AudioDemoPlaybackPage::fileClicked (const File&, const MouseEvent&)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ public:
|
|||
void selectionChanged();
|
||||
void fileClicked (const File& file, const MouseEvent& e);
|
||||
void fileDoubleClicked (const File& file);
|
||||
void showFile (const File& file);
|
||||
//[/UserMethods]
|
||||
|
||||
void paint (Graphics& g);
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@
|
|||
reduce code size.
|
||||
*/
|
||||
#if (! defined (JUCE_USE_CDBURNER)) && ! (JUCE_WINDOWS && ! JUCE_MSVC)
|
||||
#define JUCE_USE_CDBURNER 0
|
||||
#define JUCE_USE_CDBURNER 1
|
||||
#endif
|
||||
|
||||
/** JUCE_USE_CDREADER: Enables the audio CD reader code (Mac and Windows only).
|
||||
|
|
@ -155,7 +155,7 @@
|
|||
reduce code size.
|
||||
*/
|
||||
#ifndef JUCE_USE_CDREADER
|
||||
#define JUCE_USE_CDREADER 0
|
||||
#define JUCE_USE_CDREADER 1
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
|
|
@ -244,7 +244,7 @@
|
|||
Carbon isn't required for a normal app, but may be needed by specialised classes like
|
||||
plugin-hosts, which support older APIs.
|
||||
*/
|
||||
#ifndef JUCE_SUPPORT_CARBON
|
||||
#if ! (defined (JUCE_SUPPORT_CARBON) || defined (__LP64__))
|
||||
#define JUCE_SUPPORT_CARBON 1
|
||||
#endif
|
||||
|
||||
|
|
|
|||
1333
juce_amalgamated.cpp
1333
juce_amalgamated.cpp
File diff suppressed because it is too large
Load diff
1190
juce_amalgamated.h
1190
juce_amalgamated.h
File diff suppressed because it is too large
Load diff
|
|
@ -32,6 +32,7 @@ BEGIN_JUCE_NAMESPACE
|
|||
#include "../../core/juce_PlatformUtilities.h"
|
||||
#include "../../text/juce_LocalisedStrings.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
static const char* const aiffFormatName = "AIFF file";
|
||||
static const char* const aiffExtensions[] = { ".aiff", ".aif", 0 };
|
||||
|
|
@ -72,14 +73,14 @@ public:
|
|||
hasGotVer = true;
|
||||
|
||||
const int ver = input->readIntBigEndian();
|
||||
if (ver != 0 && ver != (int)0xa2805140)
|
||||
if (ver != 0 && ver != (int) 0xa2805140)
|
||||
break;
|
||||
}
|
||||
else if (type == chunkName ("COMM"))
|
||||
{
|
||||
hasGotType = true;
|
||||
|
||||
numChannels = (unsigned int)input->readShortBigEndian();
|
||||
numChannels = (unsigned int) input->readShortBigEndian();
|
||||
lengthInSamples = input->readIntBigEndian();
|
||||
bitsPerSample = input->readShortBigEndian();
|
||||
bytesPerFrame = (numChannels * bitsPerSample) >> 3;
|
||||
|
|
@ -167,318 +168,42 @@ public:
|
|||
|
||||
input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame);
|
||||
|
||||
const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
|
||||
char tempBuffer [tempBufSize];
|
||||
|
||||
while (numSamples > 0)
|
||||
{
|
||||
int* left = destSamples[0];
|
||||
if (left != 0)
|
||||
left += startOffsetInDestBuffer;
|
||||
|
||||
int* right = numDestChannels > 1 ? destSamples[1] : 0;
|
||||
if (right != 0)
|
||||
right += startOffsetInDestBuffer;
|
||||
const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
|
||||
char tempBuffer [tempBufSize];
|
||||
|
||||
const int numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples);
|
||||
const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame);
|
||||
|
||||
if (bytesRead < numThisTime * bytesPerFrame)
|
||||
{
|
||||
jassert (bytesRead >= 0);
|
||||
zeromem (tempBuffer + bytesRead, numThisTime * bytesPerFrame - bytesRead);
|
||||
}
|
||||
|
||||
if (bitsPerSample == 16)
|
||||
jassert (! usesFloatingPointData); // (would need to add support for this if it's possible)
|
||||
|
||||
if (littleEndian)
|
||||
{
|
||||
if (littleEndian)
|
||||
switch (bitsPerSample)
|
||||
{
|
||||
const short* src = reinterpret_cast <const short*> (tempBuffer);
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
if (left == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*right++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16;
|
||||
++src;
|
||||
}
|
||||
}
|
||||
else if (right == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
++src;
|
||||
*left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16;
|
||||
*right++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* src = tempBuffer;
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
if (left == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*right++ = ByteOrder::bigEndianShort (src) << 16;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
else if (right == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
src += 2;
|
||||
*left++ = ByteOrder::bigEndianShort (src) << 16;
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = ByteOrder::bigEndianShort (src) << 16;
|
||||
src += 2;
|
||||
*right++ = ByteOrder::bigEndianShort (src) << 16;
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = ByteOrder::bigEndianShort (src) << 16;
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 16: ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 24: ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 32: ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
else if (bitsPerSample == 24)
|
||||
else
|
||||
{
|
||||
const char* src = tempBuffer;
|
||||
|
||||
if (littleEndian)
|
||||
switch (bitsPerSample)
|
||||
{
|
||||
if (numChannels > 1)
|
||||
{
|
||||
if (left == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*right++ = ByteOrder::littleEndian24Bit (src) << 8;
|
||||
src += 6;
|
||||
}
|
||||
}
|
||||
else if (right == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
src += 3;
|
||||
*left++ = ByteOrder::littleEndian24Bit (src) << 8;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = ByteOrder::littleEndian24Bit (src) << 8;
|
||||
src += 3;
|
||||
*right++ = ByteOrder::littleEndian24Bit (src) << 8;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = ByteOrder::littleEndian24Bit (src) << 8;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numChannels > 1)
|
||||
{
|
||||
if (left == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*right++ = ByteOrder::bigEndian24Bit (src) << 8;
|
||||
src += 6;
|
||||
}
|
||||
}
|
||||
else if (right == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
src += 3;
|
||||
*left++ = ByteOrder::bigEndian24Bit (src) << 8;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = ByteOrder::bigEndian24Bit (src) << 8;
|
||||
src += 3;
|
||||
*right++ = ByteOrder::bigEndian24Bit (src) << 8;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = ByteOrder::bigEndian24Bit (src) << 8;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bitsPerSample == 32)
|
||||
{
|
||||
const unsigned int* src = reinterpret_cast <const unsigned int*> (tempBuffer);
|
||||
unsigned int* l = reinterpret_cast <unsigned int*> (left);
|
||||
unsigned int* r = reinterpret_cast <unsigned int*> (right);
|
||||
|
||||
if (littleEndian)
|
||||
{
|
||||
if (numChannels > 1)
|
||||
{
|
||||
if (l == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
++src;
|
||||
*r++ = ByteOrder::swapIfBigEndian (*src++);
|
||||
}
|
||||
}
|
||||
else if (r == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*l++ = ByteOrder::swapIfBigEndian (*src++);
|
||||
++src;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*l++ = ByteOrder::swapIfBigEndian (*src++);
|
||||
*r++ = ByteOrder::swapIfBigEndian (*src++);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*l++ = ByteOrder::swapIfBigEndian (*src++);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numChannels > 1)
|
||||
{
|
||||
if (l == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
++src;
|
||||
*r++ = ByteOrder::swapIfLittleEndian (*src++);
|
||||
}
|
||||
}
|
||||
else if (r == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*l++ = ByteOrder::swapIfLittleEndian (*src++);
|
||||
++src;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*l++ = ByteOrder::swapIfLittleEndian (*src++);
|
||||
*r++ = ByteOrder::swapIfLittleEndian (*src++);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*l++ = ByteOrder::swapIfLittleEndian (*src++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
left = reinterpret_cast <int*> (l);
|
||||
right = reinterpret_cast <int*> (r);
|
||||
}
|
||||
else if (bitsPerSample == 8)
|
||||
{
|
||||
const char* src = tempBuffer;
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
if (left == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*right++ = ((int) *src++) << 24;
|
||||
++src;
|
||||
}
|
||||
}
|
||||
else if (right == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
++src;
|
||||
*left++ = ((int) *src++) << 24;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = ((int) *src++) << 24;
|
||||
*right++ = ((int) *src++) << 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = ((int) *src++) << 24;
|
||||
}
|
||||
case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 16: ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 24: ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 32: ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -486,14 +211,6 @@ public:
|
|||
numSamples -= numThisTime;
|
||||
}
|
||||
|
||||
if (numSamples > 0)
|
||||
{
|
||||
for (int i = numDestChannels; --i >= 0;)
|
||||
if (destSamples[i] != 0)
|
||||
zeromem (destSamples[i] + startOffsetInDestBuffer,
|
||||
sizeof (int) * numSamples);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -509,6 +226,68 @@ private:
|
|||
//==============================================================================
|
||||
class AiffAudioFormatWriter : public AudioFormatWriter
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
AiffAudioFormatWriter (OutputStream* out, double sampleRate_, unsigned int numChans, int bits)
|
||||
: AudioFormatWriter (out, TRANS (aiffFormatName), sampleRate_, numChans, bits),
|
||||
lengthInSamples (0),
|
||||
bytesWritten (0),
|
||||
writeFailed (false)
|
||||
{
|
||||
headerPosition = out->getPosition();
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
~AiffAudioFormatWriter()
|
||||
{
|
||||
if ((bytesWritten & 1) != 0)
|
||||
output->writeByte (0);
|
||||
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool write (const int** data, int numSamples)
|
||||
{
|
||||
jassert (data != 0 && *data != 0); // the input must contain at least one channel!
|
||||
|
||||
if (writeFailed)
|
||||
return false;
|
||||
|
||||
const int bytes = numChannels * numSamples * bitsPerSample / 8;
|
||||
tempBlock.ensureSize (bytes, false);
|
||||
|
||||
switch (bitsPerSample)
|
||||
{
|
||||
case 8: WriteHelper<AudioData::Int8, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
|
||||
case 16: WriteHelper<AudioData::Int16, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
|
||||
case 24: WriteHelper<AudioData::Int24, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
|
||||
case 32: WriteHelper<AudioData::Int32, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
if (bytesWritten + bytes >= (uint32) 0xfff00000
|
||||
|| ! output->write (tempBlock.getData(), bytes))
|
||||
{
|
||||
// failed to write to disk, so let's try writing the header.
|
||||
// If it's just run out of disk space, then if it does manage
|
||||
// to write the header, we'll still have a useable file..
|
||||
writeHeader();
|
||||
writeFailed = true;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytesWritten += bytes;
|
||||
lengthInSamples += numSamples;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
MemoryBlock tempBlock;
|
||||
uint32 lengthInSamples, bytesWritten;
|
||||
int64 headerPosition;
|
||||
|
|
@ -592,153 +371,6 @@ class AiffAudioFormatWriter : public AudioFormatWriter
|
|||
|
||||
jassert (output->getPosition() == headerLen);
|
||||
}
|
||||
|
||||
public:
|
||||
//==============================================================================
|
||||
AiffAudioFormatWriter (OutputStream* out,
|
||||
const double sampleRate_,
|
||||
const unsigned int chans,
|
||||
const int bits)
|
||||
: AudioFormatWriter (out,
|
||||
TRANS (aiffFormatName),
|
||||
sampleRate_,
|
||||
chans,
|
||||
bits),
|
||||
lengthInSamples (0),
|
||||
bytesWritten (0),
|
||||
writeFailed (false)
|
||||
{
|
||||
headerPosition = out->getPosition();
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
~AiffAudioFormatWriter()
|
||||
{
|
||||
if ((bytesWritten & 1) != 0)
|
||||
output->writeByte (0);
|
||||
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool write (const int** data, int numSamples)
|
||||
{
|
||||
if (writeFailed)
|
||||
return false;
|
||||
|
||||
const int bytes = numChannels * numSamples * bitsPerSample / 8;
|
||||
tempBlock.ensureSize (bytes, false);
|
||||
char* buffer = static_cast <char*> (tempBlock.getData());
|
||||
|
||||
const int* left = data[0];
|
||||
const int* right = data[1];
|
||||
if (right == 0)
|
||||
right = left;
|
||||
|
||||
if (bitsPerSample == 16)
|
||||
{
|
||||
short* b = reinterpret_cast <short*> (buffer);
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
*b++ = (short) ByteOrder::swapIfLittleEndian ((uint16) (*left++ >> 16));
|
||||
*b++ = (short) ByteOrder::swapIfLittleEndian ((uint16) (*right++ >> 16));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
*b++ = (short) ByteOrder::swapIfLittleEndian ((uint16) (*left++ >> 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bitsPerSample == 24)
|
||||
{
|
||||
char* b = buffer;
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
ByteOrder::bigEndian24BitToChars (*left++ >> 8, b);
|
||||
b += 3;
|
||||
ByteOrder::bigEndian24BitToChars (*right++ >> 8, b);
|
||||
b += 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
ByteOrder::bigEndian24BitToChars (*left++ >> 8, b);
|
||||
b += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bitsPerSample == 32)
|
||||
{
|
||||
uint32* b = reinterpret_cast <uint32*> (buffer);
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
*b++ = ByteOrder::swapIfLittleEndian ((uint32) *left++);
|
||||
*b++ = ByteOrder::swapIfLittleEndian ((uint32) *right++);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
*b++ = ByteOrder::swapIfLittleEndian ((uint32) *left++);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bitsPerSample == 8)
|
||||
{
|
||||
char* b = buffer;
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
*b++ = (char) (*left++ >> 24);
|
||||
*b++ = (char) (*right++ >> 24);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
*b++ = (char) (*left++ >> 24);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bytesWritten + bytes >= (uint32) 0xfff00000
|
||||
|| ! output->write (buffer, bytes))
|
||||
{
|
||||
// failed to write to disk, so let's try writing the header.
|
||||
// If it's just run out of disk space, then if it does manage
|
||||
// to write the header, we'll still have a useable file..
|
||||
writeHeader();
|
||||
writeFailed = true;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytesWritten += bytes;
|
||||
lengthInSamples += numSamples;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
juce_UseDebuggingNewOperator
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -763,15 +395,8 @@ const Array <int> AiffAudioFormat::getPossibleBitDepths()
|
|||
return Array <int> (depths);
|
||||
}
|
||||
|
||||
bool AiffAudioFormat::canDoStereo()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AiffAudioFormat::canDoMono()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool AiffAudioFormat::canDoStereo() { return true; }
|
||||
bool AiffAudioFormat::canDoMono() { return true; }
|
||||
|
||||
#if JUCE_MAC
|
||||
bool AiffAudioFormat::canHandleFile (const File& f)
|
||||
|
|
@ -785,8 +410,7 @@ bool AiffAudioFormat::canHandleFile (const File& f)
|
|||
}
|
||||
#endif
|
||||
|
||||
AudioFormatReader* AiffAudioFormat::createReaderFor (InputStream* sourceStream,
|
||||
const bool deleteStreamIfOpeningFails)
|
||||
AudioFormatReader* AiffAudioFormat::createReaderFor (InputStream* sourceStream, const bool deleteStreamIfOpeningFails)
|
||||
{
|
||||
ScopedPointer <AiffAudioFormatReader> w (new AiffAudioFormatReader (sourceStream));
|
||||
|
||||
|
|
@ -801,18 +425,13 @@ AudioFormatReader* AiffAudioFormat::createReaderFor (InputStream* sourceStream,
|
|||
|
||||
AudioFormatWriter* AiffAudioFormat::createWriterFor (OutputStream* out,
|
||||
double sampleRate,
|
||||
unsigned int chans,
|
||||
unsigned int numberOfChannels,
|
||||
int bitsPerSample,
|
||||
const StringPairArray& /*metadataValues*/,
|
||||
int /*qualityOptionIndex*/)
|
||||
{
|
||||
if (getPossibleBitDepths().contains (bitsPerSample))
|
||||
{
|
||||
return new AiffAudioFormatWriter (out,
|
||||
sampleRate,
|
||||
chans,
|
||||
bitsPerSample);
|
||||
}
|
||||
return new AiffAudioFormatWriter (out, sampleRate, numberOfChannels, bitsPerSample);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "../../io/streams/juce_InputStream.h"
|
||||
#include "../../text/juce_StringPairArray.h"
|
||||
#include "../dsp/juce_AudioDataConverters.h"
|
||||
class AudioFormat;
|
||||
|
||||
|
||||
|
|
@ -218,6 +219,32 @@ public:
|
|||
//==============================================================================
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
protected:
|
||||
/** Used by AudioFormatReader subclasses to copy data to different formats. */
|
||||
template <class DestSampleType, class SourceSampleType, class SourceEndianness>
|
||||
struct ReadHelper
|
||||
{
|
||||
typedef AudioData::Pointer <DestSampleType, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DestType;
|
||||
typedef AudioData::Pointer <SourceSampleType, SourceEndianness, AudioData::Interleaved, AudioData::Const> SourceType;
|
||||
|
||||
static void read (int** destData, int destOffset, int numDestChannels, const void* sourceData, int numSourceChannels, int numSamples) throw()
|
||||
{
|
||||
for (int i = 0; i < numDestChannels; ++i)
|
||||
{
|
||||
if (destData[i] != 0)
|
||||
{
|
||||
DestType dest (destData[i]);
|
||||
dest += destOffset;
|
||||
|
||||
if (i < numSourceChannels)
|
||||
dest.convertSamples (SourceType (addBytesToPointer (sourceData, i * SourceType::getBytesPerSample()), numSourceChannels), numSamples);
|
||||
else
|
||||
dest.clearSamples (numSamples);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
String formatName;
|
||||
|
||||
|
|
|
|||
|
|
@ -160,6 +160,26 @@ protected:
|
|||
/** The output stream for Use by subclasses. */
|
||||
OutputStream* output;
|
||||
|
||||
/** Used by AudioFormatWriter subclasses to copy data to different formats. */
|
||||
template <class DestSampleType, class SourceSampleType, class DestEndianness>
|
||||
struct WriteHelper
|
||||
{
|
||||
typedef AudioData::Pointer <DestSampleType, DestEndianness, AudioData::Interleaved, AudioData::NonConst> DestType;
|
||||
typedef AudioData::Pointer <SourceSampleType, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SourceType;
|
||||
|
||||
static void write (void* destData, int numDestChannels, const int** source, int numSamples) throw()
|
||||
{
|
||||
for (int i = 0; i < numDestChannels; ++i)
|
||||
{
|
||||
const DestType dest (addBytesToPointer (destData, i * DestType::getBytesPerSample()), numDestChannels);
|
||||
dest.convertSamples (SourceType (*source), numSamples);
|
||||
|
||||
if (source[1] != 0)
|
||||
++source;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
String formatName;
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ BEGIN_JUCE_NAMESPACE
|
|||
static const char* const wavFormatName = "WAV file";
|
||||
static const char* const wavExtensions[] = { ".wav", ".bwf", 0 };
|
||||
|
||||
|
||||
//==============================================================================
|
||||
const char* const WavAudioFormat::bwavDescription = "bwav description";
|
||||
const char* const WavAudioFormat::bwavOriginator = "bwav originator";
|
||||
|
|
@ -258,17 +257,7 @@ struct ExtensibleWavSubFormat
|
|||
//==============================================================================
|
||||
class WavAudioFormatReader : public AudioFormatReader
|
||||
{
|
||||
int bytesPerFrame;
|
||||
int64 dataChunkStart, dataLength;
|
||||
|
||||
static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
|
||||
|
||||
WavAudioFormatReader (const WavAudioFormatReader&);
|
||||
WavAudioFormatReader& operator= (const WavAudioFormatReader&);
|
||||
|
||||
public:
|
||||
int64 bwavChunkStart, bwavSize;
|
||||
|
||||
//==============================================================================
|
||||
WavAudioFormatReader (InputStream* const in)
|
||||
: AudioFormatReader (in, TRANS (wavFormatName)),
|
||||
|
|
@ -389,6 +378,7 @@ public:
|
|||
bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
|
||||
int64 startSampleInFile, int numSamples)
|
||||
{
|
||||
jassert (destSamples != 0);
|
||||
const int64 samplesAvailable = lengthInSamples - startSampleInFile;
|
||||
|
||||
if (samplesAvailable < numSamples)
|
||||
|
|
@ -405,212 +395,129 @@ public:
|
|||
|
||||
input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame);
|
||||
|
||||
const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
|
||||
char tempBuffer [tempBufSize];
|
||||
|
||||
while (numSamples > 0)
|
||||
{
|
||||
int* left = destSamples[0];
|
||||
if (left != 0)
|
||||
left += startOffsetInDestBuffer;
|
||||
|
||||
int* right = numDestChannels > 1 ? destSamples[1] : 0;
|
||||
if (right != 0)
|
||||
right += startOffsetInDestBuffer;
|
||||
const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
|
||||
char tempBuffer [tempBufSize];
|
||||
|
||||
const int numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples);
|
||||
const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame);
|
||||
|
||||
if (bytesRead < numThisTime * bytesPerFrame)
|
||||
{
|
||||
jassert (bytesRead >= 0);
|
||||
zeromem (tempBuffer + bytesRead, numThisTime * bytesPerFrame - bytesRead);
|
||||
|
||||
if (bitsPerSample == 16)
|
||||
{
|
||||
const short* src = reinterpret_cast <const short*> (tempBuffer);
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
if (left == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
++src;
|
||||
*right++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16;
|
||||
}
|
||||
}
|
||||
else if (right == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16;
|
||||
++src;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16;
|
||||
*right++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bitsPerSample == 24)
|
||||
|
||||
switch (bitsPerSample)
|
||||
{
|
||||
const char* src = tempBuffer;
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
if (left == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
src += 3;
|
||||
*right++ = ByteOrder::littleEndian24Bit (src) << 8;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
else if (right == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = ByteOrder::littleEndian24Bit (src) << 8;
|
||||
src += 6;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < numThisTime; ++i)
|
||||
{
|
||||
*left++ = ByteOrder::littleEndian24Bit (src) << 8;
|
||||
src += 3;
|
||||
*right++ = ByteOrder::littleEndian24Bit (src) << 8;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < numThisTime; ++i)
|
||||
{
|
||||
*left++ = ByteOrder::littleEndian24Bit (src) << 8;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bitsPerSample == 32)
|
||||
{
|
||||
const unsigned int* src = (const unsigned int*) tempBuffer;
|
||||
unsigned int* l = reinterpret_cast<unsigned int*> (left);
|
||||
unsigned int* r = reinterpret_cast<unsigned int*> (right);
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
if (l == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
++src;
|
||||
*r++ = ByteOrder::swapIfBigEndian (*src++);
|
||||
}
|
||||
}
|
||||
else if (r == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*l++ = ByteOrder::swapIfBigEndian (*src++);
|
||||
++src;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*l++ = ByteOrder::swapIfBigEndian (*src++);
|
||||
*r++ = ByteOrder::swapIfBigEndian (*src++);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*l++ = ByteOrder::swapIfBigEndian (*src++);
|
||||
}
|
||||
}
|
||||
|
||||
left = reinterpret_cast<int*> (l);
|
||||
right = reinterpret_cast<int*> (r);
|
||||
}
|
||||
else if (bitsPerSample == 8)
|
||||
{
|
||||
const unsigned char* src = reinterpret_cast<const unsigned char*> (tempBuffer);
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
if (left == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
++src;
|
||||
*right++ = ((int) *src++ - 128) << 24;
|
||||
}
|
||||
}
|
||||
else if (right == 0)
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = ((int) *src++ - 128) << 24;
|
||||
++src;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = ((int) *src++ - 128) << 24;
|
||||
*right++ = ((int) *src++ - 128) << 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numThisTime; --i >= 0;)
|
||||
{
|
||||
*left++ = ((int)*src++ - 128) << 24;
|
||||
}
|
||||
}
|
||||
case 8: ReadHelper<AudioData::Int32, AudioData::UInt8, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 16: ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 24: ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 32: if (usesFloatingPointData) ReadHelper<AudioData::Float32, AudioData::Float32, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime);
|
||||
else ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
startOffsetInDestBuffer += numThisTime;
|
||||
numSamples -= numThisTime;
|
||||
}
|
||||
|
||||
if (numSamples > 0)
|
||||
{
|
||||
for (int i = numDestChannels; --i >= 0;)
|
||||
if (destSamples[i] != 0)
|
||||
zeromem (destSamples[i] + startOffsetInDestBuffer,
|
||||
sizeof (int) * numSamples);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int64 bwavChunkStart, bwavSize;
|
||||
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
ScopedPointer<AudioData::Converter> converter;
|
||||
int bytesPerFrame;
|
||||
int64 dataChunkStart, dataLength;
|
||||
|
||||
static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
|
||||
|
||||
WavAudioFormatReader (const WavAudioFormatReader&);
|
||||
WavAudioFormatReader& operator= (const WavAudioFormatReader&);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class WavAudioFormatWriter : public AudioFormatWriter
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
WavAudioFormatWriter (OutputStream* const out,
|
||||
const double sampleRate_,
|
||||
const unsigned int numChannels_,
|
||||
const int bits,
|
||||
const StringPairArray& metadataValues)
|
||||
: AudioFormatWriter (out,
|
||||
TRANS (wavFormatName),
|
||||
sampleRate_,
|
||||
numChannels_,
|
||||
bits),
|
||||
lengthInSamples (0),
|
||||
bytesWritten (0),
|
||||
writeFailed (false)
|
||||
{
|
||||
if (metadataValues.size() > 0)
|
||||
{
|
||||
bwavChunk = BWAVChunk::createFrom (metadataValues);
|
||||
smplChunk = SMPLChunk::createFrom (metadataValues);
|
||||
}
|
||||
|
||||
headerPosition = out->getPosition();
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
~WavAudioFormatWriter()
|
||||
{
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool write (const int** data, int numSamples)
|
||||
{
|
||||
jassert (data != 0 && *data != 0); // the input must contain at least one channel!
|
||||
|
||||
if (writeFailed)
|
||||
return false;
|
||||
|
||||
const int bytes = numChannels * numSamples * bitsPerSample / 8;
|
||||
tempBlock.ensureSize (bytes, false);
|
||||
|
||||
switch (bitsPerSample)
|
||||
{
|
||||
case 8: WriteHelper<AudioData::UInt8, AudioData::Int32, AudioData::LittleEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
|
||||
case 16: WriteHelper<AudioData::Int16, AudioData::Int32, AudioData::LittleEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
|
||||
case 24: WriteHelper<AudioData::Int24, AudioData::Int32, AudioData::LittleEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
|
||||
case 32: WriteHelper<AudioData::Int32, AudioData::Int32, AudioData::LittleEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
if (bytesWritten + bytes >= (uint32) 0xfff00000
|
||||
|| ! output->write (tempBlock.getData(), bytes))
|
||||
{
|
||||
// failed to write to disk, so let's try writing the header.
|
||||
// If it's just run out of disk space, then if it does manage
|
||||
// to write the header, we'll still have a useable file..
|
||||
writeHeader();
|
||||
writeFailed = true;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytesWritten += bytes;
|
||||
lengthInSamples += numSamples;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
ScopedPointer<AudioData::Converter> converter;
|
||||
MemoryBlock tempBlock, bwavChunk, smplChunk;
|
||||
uint32 lengthInSamples, bytesWritten;
|
||||
int64 headerPosition;
|
||||
|
|
@ -618,9 +525,6 @@ class WavAudioFormatWriter : public AudioFormatWriter
|
|||
|
||||
static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
|
||||
|
||||
WavAudioFormatWriter (const WavAudioFormatWriter&);
|
||||
WavAudioFormatWriter& operator= (const WavAudioFormatWriter&);
|
||||
|
||||
void writeHeader()
|
||||
{
|
||||
const bool seekedOk = output->setPosition (headerPosition);
|
||||
|
|
@ -666,156 +570,8 @@ class WavAudioFormatWriter : public AudioFormatWriter
|
|||
usesFloatingPointData = (bitsPerSample == 32);
|
||||
}
|
||||
|
||||
public:
|
||||
//==============================================================================
|
||||
WavAudioFormatWriter (OutputStream* const out,
|
||||
const double sampleRate_,
|
||||
const unsigned int numChannels_,
|
||||
const int bits,
|
||||
const StringPairArray& metadataValues)
|
||||
: AudioFormatWriter (out,
|
||||
TRANS (wavFormatName),
|
||||
sampleRate_,
|
||||
numChannels_,
|
||||
bits),
|
||||
lengthInSamples (0),
|
||||
bytesWritten (0),
|
||||
writeFailed (false)
|
||||
{
|
||||
if (metadataValues.size() > 0)
|
||||
{
|
||||
bwavChunk = BWAVChunk::createFrom (metadataValues);
|
||||
smplChunk = SMPLChunk::createFrom (metadataValues);
|
||||
}
|
||||
|
||||
headerPosition = out->getPosition();
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
~WavAudioFormatWriter()
|
||||
{
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool write (const int** data, int numSamples)
|
||||
{
|
||||
if (writeFailed)
|
||||
return false;
|
||||
|
||||
const int bytes = numChannels * numSamples * bitsPerSample / 8;
|
||||
tempBlock.ensureSize (bytes, false);
|
||||
char* buffer = static_cast <char*> (tempBlock.getData());
|
||||
|
||||
const int* left = data[0];
|
||||
const int* right = data[1];
|
||||
if (right == 0)
|
||||
right = left;
|
||||
|
||||
if (bitsPerSample == 16)
|
||||
{
|
||||
short* b = (short*) buffer;
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
*b++ = (short) ByteOrder::swapIfBigEndian ((unsigned short) (*left++ >> 16));
|
||||
*b++ = (short) ByteOrder::swapIfBigEndian ((unsigned short) (*right++ >> 16));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
*b++ = (short) ByteOrder::swapIfBigEndian ((unsigned short) (*left++ >> 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bitsPerSample == 24)
|
||||
{
|
||||
char* b = buffer;
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
ByteOrder::littleEndian24BitToChars ((*left++) >> 8, b);
|
||||
b += 3;
|
||||
ByteOrder::littleEndian24BitToChars ((*right++) >> 8, b);
|
||||
b += 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
ByteOrder::littleEndian24BitToChars ((*left++) >> 8, b);
|
||||
b += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bitsPerSample == 32)
|
||||
{
|
||||
unsigned int* b = (unsigned int*) buffer;
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
*b++ = ByteOrder::swapIfBigEndian ((unsigned int) *left++);
|
||||
*b++ = ByteOrder::swapIfBigEndian ((unsigned int) *right++);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
*b++ = ByteOrder::swapIfBigEndian ((unsigned int) *left++);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bitsPerSample == 8)
|
||||
{
|
||||
unsigned char* b = (unsigned char*) buffer;
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
*b++ = (unsigned char) (128 + (*left++ >> 24));
|
||||
*b++ = (unsigned char) (128 + (*right++ >> 24));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
*b++ = (unsigned char) (128 + (*left++ >> 24));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bytesWritten + bytes >= (uint32) 0xfff00000
|
||||
|| ! output->write (buffer, bytes))
|
||||
{
|
||||
// failed to write to disk, so let's try writing the header.
|
||||
// If it's just run out of disk space, then if it does manage
|
||||
// to write the header, we'll still have a useable file..
|
||||
writeHeader();
|
||||
writeFailed = true;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytesWritten += bytes;
|
||||
lengthInSamples += numSamples;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
juce_UseDebuggingNewOperator
|
||||
WavAudioFormatWriter (const WavAudioFormatWriter&);
|
||||
WavAudioFormatWriter& operator= (const WavAudioFormatWriter&);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -840,15 +596,8 @@ const Array <int> WavAudioFormat::getPossibleBitDepths()
|
|||
return Array <int> (depths);
|
||||
}
|
||||
|
||||
bool WavAudioFormat::canDoStereo()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WavAudioFormat::canDoMono()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool WavAudioFormat::canDoStereo() { return true; }
|
||||
bool WavAudioFormat::canDoMono() { return true; }
|
||||
|
||||
AudioFormatReader* WavAudioFormat::createReaderFor (InputStream* sourceStream,
|
||||
const bool deleteStreamIfOpeningFails)
|
||||
|
|
|
|||
|
|
@ -531,7 +531,7 @@ void AudioDataConverters::deinterleaveSamples (const float* const source,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
#include "../../utilities/juce_UnitTest.h"
|
||||
|
|
@ -546,6 +546,12 @@ public:
|
|||
struct Test5
|
||||
{
|
||||
static void test (UnitTest& unitTest)
|
||||
{
|
||||
test (unitTest, false);
|
||||
test (unitTest, true);
|
||||
}
|
||||
|
||||
static void test (UnitTest& unitTest, bool inPlace)
|
||||
{
|
||||
const int numSamples = 2048;
|
||||
int32 original [numSamples], converted [numSamples], reversed [numSamples];
|
||||
|
|
@ -572,13 +578,15 @@ public:
|
|||
// convert data from the source to dest format..
|
||||
ScopedPointer<AudioData::Converter> conv (new AudioData::ConverterInstance <AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>,
|
||||
AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::NonConst> >());
|
||||
conv->convertSamples (converted, original, numSamples);
|
||||
conv->convertSamples (inPlace ? reversed : converted, original, numSamples);
|
||||
|
||||
// ..and back again..
|
||||
conv = new AudioData::ConverterInstance <AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>,
|
||||
AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst> >();
|
||||
zerostruct (reversed);
|
||||
conv->convertSamples (reversed, converted, numSamples);
|
||||
if (! inPlace)
|
||||
zerostruct (reversed);
|
||||
|
||||
conv->convertSamples (reversed, inPlace ? reversed : converted, numSamples);
|
||||
|
||||
{
|
||||
int biggestDiff = 0;
|
||||
|
|
@ -615,11 +623,12 @@ public:
|
|||
{
|
||||
static void test (UnitTest& unitTest)
|
||||
{
|
||||
Test3 <FormatType, Endianness, AudioData::Int8>::test (unitTest);
|
||||
Test3 <FormatType, Endianness, AudioData::UInt8>::test (unitTest);
|
||||
Test3 <FormatType, Endianness, AudioData::Int16>::test (unitTest);
|
||||
Test3 <FormatType, Endianness, AudioData::Int24>::test (unitTest);
|
||||
Test3 <FormatType, Endianness, AudioData::Int32>::test (unitTest);
|
||||
Test3 <FormatType, Endianness, AudioData::Float32>::test (unitTest);
|
||||
Test3 <FormatType, Endianness, AudioData::Int8>::test (unitTest);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -648,6 +657,6 @@ public:
|
|||
static AudioConversionTests audioConversionUnitTests;
|
||||
|
||||
#endif
|
||||
*/
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__
|
||||
#define __JUCE_AUDIODATACONVERTERS_JUCEHEADER__
|
||||
|
||||
#if 0
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
|
|
@ -42,6 +41,7 @@ public:
|
|||
// These types can be used as the SampleFormat template parameter for the AudioData::Pointer class.
|
||||
|
||||
class Int8; /**< Used as a template parameter for AudioData::Pointer. Indicates an 8-bit integer packed data format. */
|
||||
class UInt8; /**< Used as a template parameter for AudioData::Pointer. Indicates an 8-bit unsigned integer packed data format. */
|
||||
class Int16; /**< Used as a template parameter for AudioData::Pointer. Indicates an 16-bit integer packed data format. */
|
||||
class Int24; /**< Used as a template parameter for AudioData::Pointer. Indicates an 24-bit integer packed data format. */
|
||||
class Int32; /**< Used as a template parameter for AudioData::Pointer. Indicates an 32-bit integer packed data format. */
|
||||
|
|
@ -118,20 +118,19 @@ public:
|
|||
: InterleavingType (numInterleavedChannels),
|
||||
data (Constness::toVoidPtr (sourceData))
|
||||
{
|
||||
// If you're using non-interleaved data, call the other constructor! If you're using non-interleaved data,
|
||||
// you should pass NonInterleaved as the template parameter for the interleaving type!
|
||||
static_jassert (InterleavingType::isInterleavedType != 0);
|
||||
}
|
||||
|
||||
/** Creates a copy of another pointer. */
|
||||
Pointer (const Pointer& other) throw()
|
||||
: data (other.data)
|
||||
: InterleavingType (other),
|
||||
data (other.data)
|
||||
{
|
||||
}
|
||||
|
||||
Pointer& operator= (const Pointer& other) throw()
|
||||
{
|
||||
data = other.data;
|
||||
InterleavingType::copyFrom (other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -172,9 +171,12 @@ public:
|
|||
Endianness::setAsInt32 (data, newValue);
|
||||
}
|
||||
|
||||
/** Adds a number of samples to the pointer's position. */
|
||||
/** Moves the pointer along to the next sample. */
|
||||
inline Pointer& operator++() throw() { advance(); return *this; }
|
||||
|
||||
/** Moves the pointer back to the previous sample. */
|
||||
inline Pointer& operator--() throw() { advanceDataBy (data, -1); return *this; }
|
||||
|
||||
/** Adds a number of samples to the pointer's position. */
|
||||
Pointer& operator+= (int samplesToJump) throw() { advanceDataBy (data, samplesToJump); return *this; }
|
||||
|
||||
|
|
@ -203,12 +205,31 @@ public:
|
|||
static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead!
|
||||
|
||||
Pointer dest (*this);
|
||||
while (--numSamples >= 0)
|
||||
|
||||
if (source.getRawData() != getRawData() || source.getNumBytesBetweenSamples() >= getNumBytesBetweenSamples())
|
||||
{
|
||||
Endianness::copyFrom (dest.data, source);
|
||||
dest.advance();
|
||||
++source;
|
||||
while (--numSamples >= 0)
|
||||
{
|
||||
Endianness::copyFrom (dest.data, source);
|
||||
dest.advance();
|
||||
++source;
|
||||
}
|
||||
}
|
||||
else // copy backwards if we're increasing the sample width..
|
||||
{
|
||||
dest += numSamples;
|
||||
source += numSamples;
|
||||
|
||||
while (--numSamples >= 0)
|
||||
Endianness::copyFrom ((--dest).data, --source);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets a number of samples to zero. */
|
||||
void clearSamples (int numSamples) const throw()
|
||||
{
|
||||
Pointer dest (*this);
|
||||
dest.clear (dest.data, numSamples);
|
||||
}
|
||||
|
||||
/** Returns true if the pointer is using a floating-point format. */
|
||||
|
|
@ -217,9 +238,15 @@ public:
|
|||
/** Returns true if the format is big-endian. */
|
||||
static bool isBigEndian() throw() { return (bool) Endianness::isBigEndian; }
|
||||
|
||||
/** Returns the number of bytes in each sample (ignoring the number of interleaved channels). */
|
||||
static int getBytesPerSample() throw() { return (int) SampleFormat::bytesPerSample; }
|
||||
|
||||
/** Returns the number of interleaved channels in the format. */
|
||||
int getNumInterleavedChannels() const throw() { return (int) this->numInterleavedChannels; }
|
||||
|
||||
/** Returns the number of bytes between the start address of each sample. */
|
||||
int getNumBytesBetweenSamples() const throw() { return InterleavingType::getNumBytesBetweenSamples (data); }
|
||||
|
||||
/** Returns the accuracy of this format when represented as a 32-bit integer.
|
||||
This is the smallest number above 0 that can be represented in the sample format, converted to
|
||||
a 32-bit range. E,g. if the format is 8-bit, its resolution is 0x01000000; if the format is 24-bit,
|
||||
|
|
@ -227,6 +254,9 @@ public:
|
|||
*/
|
||||
static int get32BitResolution() throw() { return (int) SampleFormat::resolution; }
|
||||
|
||||
/** Returns a pointer to the underlying data. */
|
||||
const void* getRawData() const throw() { return data.data; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
SampleFormat data;
|
||||
|
|
@ -248,9 +278,15 @@ public:
|
|||
public:
|
||||
virtual ~Converter() {}
|
||||
|
||||
/**
|
||||
/** Converts a sequence of samples from the converter's source format into the dest format. */
|
||||
virtual void convertSamples (void* destSamples, const void* sourceSamples, int numSamples) const = 0;
|
||||
|
||||
/** Converts a sequence of samples from the converter's source format into the dest format.
|
||||
This method takes sub-channel indexes, which can be used with interleaved formats in order to choose a
|
||||
particular sub-channel of the data to be used.
|
||||
*/
|
||||
virtual void convertSamples (void* dest, const void* source, int numSamples) const = 0;
|
||||
virtual void convertSamples (void* destSamples, int destSubChannel,
|
||||
const void* sourceSamples, int sourceSubChannel, int numSamples) const = 0;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -266,19 +302,34 @@ public:
|
|||
class ConverterInstance : public Converter
|
||||
{
|
||||
public:
|
||||
ConverterInstance() {}
|
||||
ConverterInstance (int numSourceChannels = 1, int numDestChannels = 1)
|
||||
: sourceChannels (numSourceChannels), destChannels (numDestChannels)
|
||||
{}
|
||||
|
||||
~ConverterInstance() {}
|
||||
|
||||
void convertSamples (void* dest, const void* source, int numSamples) const
|
||||
{
|
||||
SourceSampleType s (source);
|
||||
DestSampleType d (dest);
|
||||
SourceSampleType s (source, sourceChannels);
|
||||
DestSampleType d (dest, destChannels);
|
||||
d.convertSamples (s, numSamples);
|
||||
}
|
||||
|
||||
void convertSamples (void* dest, int destSubChannel,
|
||||
const void* source, int sourceSubChannel, int numSamples) const
|
||||
{
|
||||
jassert (destSubChannel < destChannels && sourceSubChannel < sourceChannels);
|
||||
|
||||
SourceSampleType s (addBytesToPointer (source, sourceSubChannel * SourceSampleType::getBytesPerSample()), sourceChannels);
|
||||
DestSampleType d (addBytesToPointer (dest, destSubChannel * DestSampleType::getBytesPerSample()), destChannels);
|
||||
d.convertSamples (s, numSamples);
|
||||
}
|
||||
|
||||
private:
|
||||
ConverterInstance (const ConverterInstance&);
|
||||
ConverterInstance& operator= (const ConverterInstance&);
|
||||
|
||||
const int sourceChannels, destChannels;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -324,18 +375,45 @@ public:
|
|||
inline void skip (int numSamples) throw() { data += numSamples; }
|
||||
inline float getAsFloatLE() const throw() { return (float) (*data * (1.0 / (1.0 + maxValue))); }
|
||||
inline float getAsFloatBE() const throw() { return getAsFloatLE(); }
|
||||
inline void setAsFloatLE (float newValue) throw() { *data = jlimit ((int8) -maxValue, (int8) maxValue, (int8) roundToInt (newValue * (1.0 + maxValue))); }
|
||||
inline void setAsFloatLE (float newValue) throw() { *data = (int8) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))); }
|
||||
inline void setAsFloatBE (float newValue) throw() { setAsFloatLE (newValue); }
|
||||
inline int32 getAsInt32LE() const throw() { return (int) (*data << 24); }
|
||||
inline int32 getAsInt32BE() const throw() { return getAsInt32LE(); }
|
||||
inline void setAsInt32LE (int newValue) throw() { *data = (int8) (newValue >> 24); }
|
||||
inline void setAsInt32BE (int newValue) throw() { setAsInt32LE (newValue); }
|
||||
inline void clear() throw() { *data = 0; }
|
||||
inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;}
|
||||
template <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); }
|
||||
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); }
|
||||
inline void copyFromSameType (Int8& source) throw() { *data = *source.data; }
|
||||
|
||||
int8* data;
|
||||
enum { maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 };
|
||||
enum { bytesPerSample = 1, maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 };
|
||||
};
|
||||
|
||||
class AudioData::UInt8
|
||||
{
|
||||
public:
|
||||
inline UInt8 (void* data_) throw() : data (static_cast <uint8*> (data_)) {}
|
||||
|
||||
inline void advance() throw() { ++data; }
|
||||
inline void skip (int numSamples) throw() { data += numSamples; }
|
||||
inline float getAsFloatLE() const throw() { return (float) ((*data - 128) * (1.0 / (1.0 + maxValue))); }
|
||||
inline float getAsFloatBE() const throw() { return getAsFloatLE(); }
|
||||
inline void setAsFloatLE (float newValue) throw() { *data = (uint8) jlimit (0, 255, 128 + roundToInt (newValue * (1.0 + maxValue))); }
|
||||
inline void setAsFloatBE (float newValue) throw() { setAsFloatLE (newValue); }
|
||||
inline int32 getAsInt32LE() const throw() { return (int) ((*data - 128) << 24); }
|
||||
inline int32 getAsInt32BE() const throw() { return getAsInt32LE(); }
|
||||
inline void setAsInt32LE (int newValue) throw() { *data = (uint8) (128 + (newValue >> 24)); }
|
||||
inline void setAsInt32BE (int newValue) throw() { setAsInt32LE (newValue); }
|
||||
inline void clear() throw() { *data = 128; }
|
||||
inline void clearMultiple (int num) throw() { memset (data, 128, num) ;}
|
||||
template <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); }
|
||||
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); }
|
||||
inline void copyFromSameType (UInt8& source) throw() { *data = *source.data; }
|
||||
|
||||
uint8* data;
|
||||
enum { bytesPerSample = 1, maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 };
|
||||
};
|
||||
|
||||
class AudioData::Int16
|
||||
|
|
@ -353,12 +431,14 @@ public:
|
|||
inline int32 getAsInt32BE() const throw() { return (int32) (ByteOrder::swapIfLittleEndian ((uint16) *data) << 16); }
|
||||
inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) (newValue >> 16)); }
|
||||
inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) (newValue >> 16)); }
|
||||
inline void clear() throw() { *data = 0; }
|
||||
inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;}
|
||||
template <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); }
|
||||
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); }
|
||||
inline void copyFromSameType (Int16& source) throw() { *data = *source.data; }
|
||||
|
||||
uint16* data;
|
||||
enum { maxValue = 0x7fff, resolution = (1 << 16), isFloat = 0 };
|
||||
enum { bytesPerSample = 2, maxValue = 0x7fff, resolution = (1 << 16), isFloat = 0 };
|
||||
};
|
||||
|
||||
class AudioData::Int24
|
||||
|
|
@ -376,12 +456,14 @@ public:
|
|||
inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::bigEndian24Bit (data) << 8; }
|
||||
inline void setAsInt32LE (int32 newValue) throw() { ByteOrder::littleEndian24BitToChars (newValue >> 8, data); }
|
||||
inline void setAsInt32BE (int32 newValue) throw() { ByteOrder::bigEndian24BitToChars (newValue >> 8, data); }
|
||||
inline void clear() throw() { data[0] = 0; data[1] = 0; data[2] = 0; }
|
||||
inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;}
|
||||
template <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); }
|
||||
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); }
|
||||
inline void copyFromSameType (Int24& source) throw() { data[0] = source.data[0]; data[1] = source.data[1]; data[2] = source.data[2]; }
|
||||
|
||||
char* data;
|
||||
enum { maxValue = 0x7fffff, resolution = (1 << 8), isFloat = 0 };
|
||||
enum { bytesPerSample = 3, maxValue = 0x7fffff, resolution = (1 << 8), isFloat = 0 };
|
||||
};
|
||||
|
||||
class AudioData::Int32
|
||||
|
|
@ -399,12 +481,14 @@ public:
|
|||
inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::swapIfLittleEndian (*data); }
|
||||
inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); }
|
||||
inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) newValue); }
|
||||
inline void clear() throw() { *data = 0; }
|
||||
inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;}
|
||||
template <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); }
|
||||
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); }
|
||||
inline void copyFromSameType (Int32& source) throw() { *data = *source.data; }
|
||||
|
||||
uint32* data;
|
||||
enum { maxValue = 0x7fffffff, resolution = 1, isFloat = 0 };
|
||||
enum { bytesPerSample = 4, maxValue = 0x7fffffff, resolution = 1, isFloat = 0 };
|
||||
};
|
||||
|
||||
class AudioData::Float32
|
||||
|
|
@ -429,12 +513,14 @@ public:
|
|||
inline int32 getAsInt32BE() const throw() { return (int32) roundToInt (jlimit (-1.0f, 1.0f, getAsFloatBE()) * (1.0 + maxValue)); }
|
||||
inline void setAsInt32LE (int32 newValue) throw() { setAsFloatLE ((float) (newValue * (1.0 / (1.0 + maxValue)))); }
|
||||
inline void setAsInt32BE (int32 newValue) throw() { setAsFloatBE ((float) (newValue * (1.0 / (1.0 + maxValue)))); }
|
||||
inline void clear() throw() { *data = 0; }
|
||||
inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;}
|
||||
template <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); }
|
||||
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsFloatBE (source.getAsFloat()); }
|
||||
inline void copyFromSameType (Float32& source) throw() { *data = *source.data; }
|
||||
|
||||
float* data;
|
||||
enum { maxValue = 0x7fffffff, resolution = (1 << 8), isFloat = 1 };
|
||||
enum { bytesPerSample = 4, maxValue = 0x7fffffff, resolution = (1 << 8), isFloat = 1 };
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -442,9 +528,14 @@ class AudioData::NonInterleaved
|
|||
{
|
||||
public:
|
||||
inline NonInterleaved() throw() {}
|
||||
inline NonInterleaved (const NonInterleaved&) throw() {}
|
||||
inline NonInterleaved (const int) throw() {}
|
||||
template <class SampleFormatType> inline void advanceData (SampleFormatType& s) throw() { s.advance(); }
|
||||
template <class SampleFormatType> inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numSamples); }
|
||||
inline void copyFrom (const NonInterleaved&) throw() {}
|
||||
template <class SampleFormatType> inline void advanceData (SampleFormatType& s) throw() { s.advance(); }
|
||||
template <class SampleFormatType> inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numSamples); }
|
||||
template <class SampleFormatType> inline void clear (SampleFormatType& s, int numSamples) throw() { s.clearMultiple (numSamples); }
|
||||
template <class SampleFormatType> inline static int getNumBytesBetweenSamples (const SampleFormatType&) throw() { return SampleFormatType::bytesPerSample; }
|
||||
|
||||
enum { isInterleavedType = 0, numInterleavedChannels = 1 };
|
||||
};
|
||||
|
||||
|
|
@ -452,14 +543,15 @@ class AudioData::Interleaved
|
|||
{
|
||||
public:
|
||||
inline Interleaved() throw() : numInterleavedChannels (1) {}
|
||||
inline Interleaved (const Interleaved& other) throw() : numInterleavedChannels (other.numInterleavedChannels) {}
|
||||
inline Interleaved (const int numInterleavedChannels_) throw() : numInterleavedChannels (numInterleavedChannels_) {}
|
||||
inline void copyFrom (const Interleaved& other) throw() { numInterleavedChannels = other.numInterleavedChannels; }
|
||||
template <class SampleFormatType> inline void advanceData (SampleFormatType& s) throw() { s.skip (numInterleavedChannels); }
|
||||
template <class SampleFormatType> inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numInterleavedChannels * numSamples); }
|
||||
const int numInterleavedChannels;
|
||||
template <class SampleFormatType> inline void clear (SampleFormatType& s, int numSamples) throw() { while (--numSamples >= 0) { s.clear(); s.skip (numInterleavedChannels); } }
|
||||
template <class SampleFormatType> inline int getNumBytesBetweenSamples (const SampleFormatType& s) const throw() { return numInterleavedChannels * s.bytesPerSample; }
|
||||
int numInterleavedChannels;
|
||||
enum { isInterleavedType = 1 };
|
||||
|
||||
private:
|
||||
Interleaved& operator= (const Interleaved&);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -481,8 +573,6 @@ public:
|
|||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A set of routines to convert buffers of 32-bit floating point data to and from
|
||||
|
|
|
|||
|
|
@ -528,13 +528,17 @@ public:
|
|||
/** Removes a previously added listener. */
|
||||
void removeListener (AudioProcessorListener* listenerToRemove);
|
||||
|
||||
//==============================================================================
|
||||
/** Tells the processor to use this playhead object.
|
||||
The processor will not take ownership of the object, so the caller must delete it when
|
||||
it is no longer being used.
|
||||
*/
|
||||
void setPlayHead (AudioPlayHead* newPlayHead) throw();
|
||||
|
||||
//==============================================================================
|
||||
/** Not for public use - this is called before deleting an editor component. */
|
||||
void editorBeingDeleted (AudioProcessorEditor* editor) throw();
|
||||
|
||||
/** Not for public use - this is called to initialise the processor. */
|
||||
void setPlayHead (AudioPlayHead* newPlayHead) throw();
|
||||
|
||||
/** Not for public use - this is called to initialise the processor before playing. */
|
||||
void setPlayConfigDetails (int numIns, int numOuts,
|
||||
double sampleRate,
|
||||
|
|
|
|||
|
|
@ -122,6 +122,12 @@ public:
|
|||
*/
|
||||
inline operator void*() const throw() { return static_cast <void*> (data); }
|
||||
|
||||
/** Returns a void pointer to the allocated data.
|
||||
This may be a null pointer if the data hasn't yet been allocated, or if it has been
|
||||
freed by calling the free() method.
|
||||
*/
|
||||
inline operator const void*() const throw() { return static_cast <const void*> (data); }
|
||||
|
||||
/** Lets you use indirect calls to the first element in the array.
|
||||
Obviously this will cause problems if the array hasn't been initialised, because it'll
|
||||
be referencing a null pointer.
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ public:
|
|||
class var::VariantType_Void : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Void() {}
|
||||
static const VariantType_Void* getInstance() { static const VariantType_Void i; return &i; }
|
||||
|
||||
bool isVoid() const throw() { return true; }
|
||||
|
|
@ -74,6 +75,7 @@ public:
|
|||
class var::VariantType_Int : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Int() {}
|
||||
static const VariantType_Int* getInstance() { static const VariantType_Int i; return &i; }
|
||||
|
||||
int toInt (const ValueUnion& data) const { return data.intValue; };
|
||||
|
|
@ -100,6 +102,7 @@ public:
|
|||
class var::VariantType_Double : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Double() {}
|
||||
static const VariantType_Double* getInstance() { static const VariantType_Double i; return &i; }
|
||||
|
||||
int toInt (const ValueUnion& data) const { return (int) data.doubleValue; };
|
||||
|
|
@ -126,6 +129,7 @@ public:
|
|||
class var::VariantType_Bool : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Bool() {}
|
||||
static const VariantType_Bool* getInstance() { static const VariantType_Bool i; return &i; }
|
||||
|
||||
int toInt (const ValueUnion& data) const { return data.boolValue ? 1 : 0; };
|
||||
|
|
@ -151,6 +155,7 @@ public:
|
|||
class var::VariantType_String : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_String() {}
|
||||
static const VariantType_String* getInstance() { static const VariantType_String i; return &i; }
|
||||
|
||||
void cleanUp (ValueUnion& data) const throw() { delete data.stringValue; }
|
||||
|
|
@ -185,6 +190,7 @@ public:
|
|||
class var::VariantType_Object : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Object() {}
|
||||
static const VariantType_Object* getInstance() { static const VariantType_Object i; return &i; }
|
||||
|
||||
void cleanUp (ValueUnion& data) const throw() { if (data.objectValue != 0) data.objectValue->decReferenceCount(); }
|
||||
|
|
@ -212,6 +218,7 @@ public:
|
|||
class var::VariantType_Method : public var::VariantType
|
||||
{
|
||||
public:
|
||||
VariantType_Method() {}
|
||||
static const VariantType_Method* getInstance() { static const VariantType_Method i; return &i; }
|
||||
|
||||
const String toString (const ValueUnion&) const { return "Method"; }
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
*/
|
||||
#define JUCE_MAJOR_VERSION 1
|
||||
#define JUCE_MINOR_VERSION 52
|
||||
#define JUCE_BUILDNUMBER 69
|
||||
#define JUCE_BUILDNUMBER 70
|
||||
|
||||
/** Current Juce version number.
|
||||
|
||||
|
|
|
|||
|
|
@ -525,7 +525,7 @@ public:
|
|||
|
||||
@see Component::createComponentSnapshot
|
||||
*/
|
||||
const Image createSnapshotOfSelectedRows (int& x, int& y);
|
||||
virtual const Image createSnapshotOfSelectedRows (int& x, int& y);
|
||||
|
||||
/** Returns the viewport that this ListBox uses.
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ static void getDeviceProperties (const String& deviceID,
|
|||
if (snd_ctl_pcm_info (handle, info) >= 0)
|
||||
{
|
||||
snd_pcm_t* pcmHandle;
|
||||
if (snd_pcm_open (&pcmHandle, deviceID.toUTF8(), SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC | SND_PCM_NONBLOCK ) >= 0)
|
||||
if (snd_pcm_open (&pcmHandle, deviceID.toUTF8(), SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC | SND_PCM_NONBLOCK) >= 0)
|
||||
{
|
||||
getDeviceNumChannels (pcmHandle, &minChansOut, &maxChansOut);
|
||||
getDeviceSampleRates (pcmHandle, rates);
|
||||
|
|
@ -96,7 +96,7 @@ static void getDeviceProperties (const String& deviceID,
|
|||
if (snd_ctl_pcm_info (handle, info) >= 0)
|
||||
{
|
||||
snd_pcm_t* pcmHandle;
|
||||
if (snd_pcm_open (&pcmHandle, deviceID.toUTF8(), SND_PCM_STREAM_CAPTURE, SND_PCM_ASYNC | SND_PCM_NONBLOCK ) >= 0)
|
||||
if (snd_pcm_open (&pcmHandle, deviceID.toUTF8(), SND_PCM_STREAM_CAPTURE, SND_PCM_ASYNC | SND_PCM_NONBLOCK) >= 0)
|
||||
{
|
||||
getDeviceNumChannels (pcmHandle, &minChansIn, &maxChansIn);
|
||||
|
||||
|
|
@ -115,14 +115,12 @@ static void getDeviceProperties (const String& deviceID,
|
|||
class ALSADevice
|
||||
{
|
||||
public:
|
||||
ALSADevice (const String& deviceID,
|
||||
const bool forInput)
|
||||
ALSADevice (const String& deviceID, bool forInput)
|
||||
: handle (0),
|
||||
bitDepth (16),
|
||||
numChannelsRunning (0),
|
||||
latency (0),
|
||||
isInput (forInput),
|
||||
sampleFormat (AudioDataConverters::int16LE)
|
||||
isInput (forInput)
|
||||
{
|
||||
failed (snd_pcm_open (&handle, deviceID.toUTF8(),
|
||||
forInput ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
|
||||
|
|
@ -156,22 +154,26 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
const int formatsToTry[] = { SND_PCM_FORMAT_FLOAT_LE, 32, AudioDataConverters::float32LE,
|
||||
SND_PCM_FORMAT_FLOAT_BE, 32, AudioDataConverters::float32BE,
|
||||
SND_PCM_FORMAT_S32_LE, 32, AudioDataConverters::int32LE,
|
||||
SND_PCM_FORMAT_S32_BE, 32, AudioDataConverters::int32BE,
|
||||
SND_PCM_FORMAT_S24_3LE, 24, AudioDataConverters::int24LE,
|
||||
SND_PCM_FORMAT_S24_3BE, 24, AudioDataConverters::int24BE,
|
||||
SND_PCM_FORMAT_S16_LE, 16, AudioDataConverters::int16LE,
|
||||
SND_PCM_FORMAT_S16_BE, 16, AudioDataConverters::int16BE };
|
||||
enum { isFloatBit = 1 << 16, isLittleEndianBit = 1 << 17 };
|
||||
|
||||
const int formatsToTry[] = { SND_PCM_FORMAT_FLOAT_LE, 32 | isFloatBit | isLittleEndianBit,
|
||||
SND_PCM_FORMAT_FLOAT_BE, 32 | isFloatBit,
|
||||
SND_PCM_FORMAT_S32_LE, 32 | isLittleEndianBit,
|
||||
SND_PCM_FORMAT_S32_BE, 32,
|
||||
SND_PCM_FORMAT_S24_3LE, 24 | isLittleEndianBit,
|
||||
SND_PCM_FORMAT_S24_3BE, 24,
|
||||
SND_PCM_FORMAT_S16_LE, 16 | isLittleEndianBit,
|
||||
SND_PCM_FORMAT_S16_BE, 16 };
|
||||
bitDepth = 0;
|
||||
|
||||
for (int i = 0; i < numElementsInArray (formatsToTry); i += 3)
|
||||
for (int i = 0; i < numElementsInArray (formatsToTry); i += 2)
|
||||
{
|
||||
if (snd_pcm_hw_params_set_format (handle, hwParams, (_snd_pcm_format) formatsToTry [i]) >= 0)
|
||||
{
|
||||
bitDepth = formatsToTry [i + 1];
|
||||
sampleFormat = (AudioDataConverters::DataFormat) formatsToTry [i + 2];
|
||||
bitDepth = formatsToTry [i + 1] & 255;
|
||||
const bool isFloat = (formatsToTry [i + 1] & isFloatBit) != 0;
|
||||
const bool isLittleEndian = (formatsToTry [i + 1] & isLittleEndianBit) != 0;
|
||||
converter = createConverter (isInput, bitDepth, isFloat, isLittleEndian, numChannels);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -235,48 +237,44 @@ public:
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
bool write (AudioSampleBuffer& outputChannelBuffer, const int numSamples)
|
||||
bool writeToOutputDevice (AudioSampleBuffer& outputChannelBuffer, const int numSamples)
|
||||
{
|
||||
jassert (numChannelsRunning <= outputChannelBuffer.getNumChannels());
|
||||
float** const data = outputChannelBuffer.getArrayOfChannels();
|
||||
snd_pcm_sframes_t numDone = 0;
|
||||
|
||||
if (isInterleaved)
|
||||
{
|
||||
scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
|
||||
float* interleaved = static_cast <float*> (scratch.getData());
|
||||
|
||||
AudioDataConverters::interleaveSamples ((const float**) data, interleaved, numSamples, numChannelsRunning);
|
||||
AudioDataConverters::convertFloatToFormat (sampleFormat, interleaved, interleaved, numSamples * numChannelsRunning);
|
||||
for (int i = 0; i < numChannelsRunning; ++i)
|
||||
converter->convertSamples (scratch.getData(), i, data[i], 0, numSamples);
|
||||
|
||||
snd_pcm_sframes_t num = snd_pcm_writei (handle, interleaved, numSamples);
|
||||
|
||||
if (failed (num) && num != -EPIPE && num != -ESTRPIPE)
|
||||
return false;
|
||||
numDone = snd_pcm_writei (handle, scratch.getData(), numSamples);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < numChannelsRunning; ++i)
|
||||
if (data[i] != 0)
|
||||
AudioDataConverters::convertFloatToFormat (sampleFormat, data[i], data[i], numSamples);
|
||||
converter->convertSamples (data[i], data[i], numSamples);
|
||||
|
||||
snd_pcm_sframes_t num = snd_pcm_writen (handle, (void**) data, numSamples);
|
||||
numDone = snd_pcm_writen (handle, (void**) data, numSamples);
|
||||
}
|
||||
|
||||
if (failed (num))
|
||||
if (failed (numDone))
|
||||
{
|
||||
if (numDone == -EPIPE)
|
||||
{
|
||||
if (num == -EPIPE)
|
||||
{
|
||||
if (failed (snd_pcm_prepare (handle)))
|
||||
return false;
|
||||
}
|
||||
else if (num != -ESTRPIPE)
|
||||
if (failed (snd_pcm_prepare (handle)))
|
||||
return false;
|
||||
}
|
||||
else if (numDone != -ESTRPIPE)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool read (AudioSampleBuffer& inputChannelBuffer, const int numSamples)
|
||||
bool readFromInputDevice (AudioSampleBuffer& inputChannelBuffer, const int numSamples)
|
||||
{
|
||||
jassert (numChannelsRunning <= inputChannelBuffer.getNumChannels());
|
||||
float** const data = inputChannelBuffer.getArrayOfChannels();
|
||||
|
|
@ -284,9 +282,8 @@ public:
|
|||
if (isInterleaved)
|
||||
{
|
||||
scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
|
||||
float* interleaved = static_cast <float*> (scratch.getData());
|
||||
|
||||
snd_pcm_sframes_t num = snd_pcm_readi (handle, interleaved, numSamples);
|
||||
snd_pcm_sframes_t num = snd_pcm_readi (handle, scratch.getData(), numSamples);
|
||||
|
||||
if (failed (num))
|
||||
{
|
||||
|
|
@ -299,8 +296,8 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
AudioDataConverters::convertFormatToFloat (sampleFormat, interleaved, interleaved, numSamples * numChannelsRunning);
|
||||
AudioDataConverters::deinterleaveSamples (interleaved, data, numSamples, numChannelsRunning);
|
||||
for (int i = 0; i < numChannelsRunning; ++i)
|
||||
converter->convertSamples (data[i], 0, scratch.getData(), i, numSamples);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -310,8 +307,7 @@ public:
|
|||
return false;
|
||||
|
||||
for (int i = 0; i < numChannelsRunning; ++i)
|
||||
if (data[i] != 0)
|
||||
AudioDataConverters::convertFormatToFloat (sampleFormat, data[i], data[i], numSamples);
|
||||
converter->convertSamples (data[i], data[i], numSamples);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -329,7 +325,48 @@ private:
|
|||
const bool isInput;
|
||||
bool isInterleaved;
|
||||
MemoryBlock scratch;
|
||||
AudioDataConverters::DataFormat sampleFormat;
|
||||
ScopedPointer<AudioData::Converter> converter;
|
||||
|
||||
//==============================================================================
|
||||
template <class SampleType>
|
||||
struct ConverterHelper
|
||||
{
|
||||
static AudioData::Converter* createConverter (const bool forInput, const bool isLittleEndian, const int numInterleavedChannels)
|
||||
{
|
||||
if (forInput)
|
||||
{
|
||||
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DestType;
|
||||
|
||||
if (isLittleEndian)
|
||||
return new AudioData::ConverterInstance <AudioData::Pointer <SampleType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, DestType> (numInterleavedChannels, 1);
|
||||
else
|
||||
return new AudioData::ConverterInstance <AudioData::Pointer <SampleType, AudioData::BigEndian, AudioData::Interleaved, AudioData::Const>, DestType> (numInterleavedChannels, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SourceType;
|
||||
|
||||
if (isLittleEndian)
|
||||
return new AudioData::ConverterInstance <SourceType, AudioData::Pointer <SampleType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, numInterleavedChannels);
|
||||
else
|
||||
return new AudioData::ConverterInstance <SourceType, AudioData::Pointer <SampleType, AudioData::BigEndian, AudioData::Interleaved, AudioData::NonConst> > (1, numInterleavedChannels);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static AudioData::Converter* createConverter (const bool forInput, const int bitDepth, const bool isFloat, const bool isLittleEndian, const int numInterleavedChannels)
|
||||
{
|
||||
switch (bitDepth)
|
||||
{
|
||||
case 16: return ConverterHelper <AudioData::Int16>::createConverter (forInput, isLittleEndian, numInterleavedChannels);
|
||||
case 24: return ConverterHelper <AudioData::Int24>::createConverter (forInput, isLittleEndian, numInterleavedChannels);
|
||||
case 32: return isFloat ? ConverterHelper <AudioData::Float32>::createConverter (forInput, isLittleEndian, numInterleavedChannels)
|
||||
: ConverterHelper <AudioData::Int32>::createConverter (forInput, isLittleEndian, numInterleavedChannels);
|
||||
default: jassertfalse; break; // unsupported format!
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool failed (const int errorNum)
|
||||
|
|
@ -522,7 +559,7 @@ public:
|
|||
{
|
||||
if (inputDevice != 0)
|
||||
{
|
||||
if (! inputDevice->read (inputChannelBuffer, bufferSize))
|
||||
if (! inputDevice->readFromInputDevice (inputChannelBuffer, bufferSize))
|
||||
{
|
||||
DBG ("ALSA: read failure");
|
||||
break;
|
||||
|
|
@ -560,7 +597,7 @@ public:
|
|||
|
||||
failed (snd_pcm_avail_update (outputDevice->handle));
|
||||
|
||||
if (! outputDevice->write (outputChannelBuffer, bufferSize))
|
||||
if (! outputDevice->writeToOutputDevice (outputChannelBuffer, bufferSize))
|
||||
{
|
||||
DBG ("ALSA: write failure");
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -279,10 +279,19 @@ END_JUCE_NAMESPACE
|
|||
|
||||
source->getNextAudioBlock (info);
|
||||
|
||||
JUCE_NAMESPACE::AudioDataConverters::convertFloatToInt16LE (tempBuffer.getSampleData (0),
|
||||
buffer, numSamples, 4);
|
||||
JUCE_NAMESPACE::AudioDataConverters::convertFloatToInt16LE (tempBuffer.getSampleData (1),
|
||||
buffer + 2, numSamples, 4);
|
||||
typedef JUCE_NAMESPACE::AudioData::Pointer <JUCE_NAMESPACE::AudioData::Int16,
|
||||
JUCE_NAMESPACE::AudioData::LittleEndian,
|
||||
JUCE_NAMESPACE::AudioData::Interleaved,
|
||||
JUCE_NAMESPACE::AudioData::NonConst> CDSampleFormat;
|
||||
|
||||
typedef JUCE_NAMESPACE::AudioData::Pointer <JUCE_NAMESPACE::AudioData::Float32,
|
||||
JUCE_NAMESPACE::AudioData::NativeEndian,
|
||||
JUCE_NAMESPACE::AudioData::NonInterleaved,
|
||||
JUCE_NAMESPACE::AudioData::Const> SourceSampleFormat;
|
||||
CDSampleFormat left (buffer, 2);
|
||||
left.convertSamples (SourceSampleFormat (tempBuffer.getSampleData (0)), numSamples);
|
||||
CDSampleFormat right (buffer + 2, 2);
|
||||
right.convertSamples (SourceSampleFormat (tempBuffer.getSampleData (1)), numSamples);
|
||||
|
||||
readPosition += numSamples;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -306,7 +306,6 @@ public:
|
|||
size = sizeof (lat);
|
||||
pa.mSelector = kAudioDevicePropertyLatency;
|
||||
pa.mScope = kAudioDevicePropertyScopeInput;
|
||||
//if (AudioDeviceGetProperty (deviceID, 0, true, kAudioDevicePropertyLatency, &size, &lat) == noErr)
|
||||
if (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &lat) == noErr)
|
||||
inputLatency = (int) lat;
|
||||
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ private:
|
|||
}
|
||||
|
||||
// If we failed to find it "properly", this dodgy fall-back seems to do the trick for most fonts!
|
||||
return jmax (-1, c - 29);
|
||||
return jmax (-1, (int) c - 29);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ public:
|
|||
JUCEApplication::appWillTerminateByForce();
|
||||
}
|
||||
|
||||
virtual BOOL openFile (const NSString* filename)
|
||||
virtual BOOL openFile (NSString* filename)
|
||||
{
|
||||
if (JUCEApplication::getInstance() != 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2378,11 +2378,16 @@ bool AudioCDBurner::addAudioTrack (AudioSource* audioSource, int numSamples)
|
|||
|
||||
zeromem (buffer, bytesPerBlock);
|
||||
|
||||
AudioDataConverters::convertFloatToInt16LE (sourceBuffer.getSampleData (0, 0),
|
||||
buffer, samplesPerBlock, 4);
|
||||
typedef AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian,
|
||||
AudioData::Interleaved, AudioData::NonConst> CDSampleFormat;
|
||||
|
||||
AudioDataConverters::convertFloatToInt16LE (sourceBuffer.getSampleData (1, 0),
|
||||
buffer + 2, samplesPerBlock, 4);
|
||||
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian,
|
||||
AudioData::NonInterleaved, AudioData::Const> SourceSampleFormat;
|
||||
|
||||
CDSampleFormat left (buffer, 2);
|
||||
left.convertSamples (SourceSampleFormat (sourceBuffer.getSampleData (0)), samplesPerBlock);
|
||||
CDSampleFormat right (buffer + 2, 2);
|
||||
right.convertSamples (SourceSampleFormat (sourceBuffer.getSampleData (1)), samplesPerBlock);
|
||||
|
||||
hr = pimpl->redbook->AddAudioTrackBlocks (buffer, bytesPerBlock);
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ DynamicLibraryLoader::~DynamicLibraryLoader()
|
|||
|
||||
void* DynamicLibraryLoader::findProcAddress (const String& functionName)
|
||||
{
|
||||
return GetProcAddress ((HMODULE) libHandle, functionName.toCString());
|
||||
return (void*) GetProcAddress ((HMODULE) libHandle, functionName.toCString()); // (void* cast is required for mingw)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ void PlatformUtilities::freeDynamicLibrary (void* h)
|
|||
|
||||
void* PlatformUtilities::getProcedureEntryPoint (void* h, const String& name)
|
||||
{
|
||||
return (h != 0) ? GetProcAddress ((HMODULE) h, name.toCString()) : 0;
|
||||
return (h != 0) ? (void*) GetProcAddress ((HMODULE) h, name.toCString()) : 0; // (void* cast is required for mingw)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -232,11 +232,12 @@ public:
|
|||
Array <double> rates;
|
||||
HANDLE clientEvent;
|
||||
BigInteger channels;
|
||||
AudioDataConverters::DataFormat dataFormat;
|
||||
Array <int> channelMaps;
|
||||
UINT32 actualBufferSize;
|
||||
int bytesPerSample;
|
||||
|
||||
virtual void updateFormat (bool isFloat) = 0;
|
||||
|
||||
private:
|
||||
const ComSmartPtr <IAudioClient> createClient()
|
||||
{
|
||||
|
|
@ -311,10 +312,8 @@ private:
|
|||
actualNumChannels = format.Format.nChannels;
|
||||
const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
||||
bytesPerSample = format.Format.wBitsPerSample / 8;
|
||||
dataFormat = isFloat ? AudioDataConverters::float32LE
|
||||
: (bytesPerSample == 4 ? AudioDataConverters::int32LE
|
||||
: ((bytesPerSample == 3 ? AudioDataConverters::int24LE
|
||||
: AudioDataConverters::int16LE)));
|
||||
|
||||
updateFormat (isFloat);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -356,6 +355,20 @@ public:
|
|||
reservoir.setSize (0);
|
||||
}
|
||||
|
||||
void updateFormat (bool isFloat)
|
||||
{
|
||||
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> NativeType;
|
||||
|
||||
if (isFloat)
|
||||
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Float32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
|
||||
else if (bytesPerSample == 4)
|
||||
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Int32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
|
||||
else if (bytesPerSample == 3)
|
||||
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Int24, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
|
||||
else
|
||||
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
|
||||
}
|
||||
|
||||
void copyBuffers (float** destBuffers, int numDestBuffers, int bufferSize, Thread& thread)
|
||||
{
|
||||
if (numChannels <= 0)
|
||||
|
|
@ -370,31 +383,7 @@ public:
|
|||
const int samplesToDo = jmin (bufferSize, (int) reservoirSize);
|
||||
|
||||
for (int i = 0; i < numDestBuffers; ++i)
|
||||
{
|
||||
float* const dest = destBuffers[i] + offset;
|
||||
const int srcChan = channelMaps.getUnchecked(i);
|
||||
|
||||
switch (dataFormat)
|
||||
{
|
||||
case AudioDataConverters::float32LE:
|
||||
AudioDataConverters::convertFloat32LEToFloat (((uint8*) reservoir.getData()) + 4 * srcChan, dest, samplesToDo, 4 * actualNumChannels);
|
||||
break;
|
||||
|
||||
case AudioDataConverters::int32LE:
|
||||
AudioDataConverters::convertInt32LEToFloat (((uint8*) reservoir.getData()) + 4 * srcChan, dest, samplesToDo, 4 * actualNumChannels);
|
||||
break;
|
||||
|
||||
case AudioDataConverters::int24LE:
|
||||
AudioDataConverters::convertInt24LEToFloat (((uint8*) reservoir.getData()) + 3 * srcChan, dest, samplesToDo, 3 * actualNumChannels);
|
||||
break;
|
||||
|
||||
case AudioDataConverters::int16LE:
|
||||
AudioDataConverters::convertInt16LEToFloat (((uint8*) reservoir.getData()) + 2 * srcChan, dest, samplesToDo, 2 * actualNumChannels);
|
||||
break;
|
||||
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
converter->convertSamples (destBuffers[i], offset, reservoir.getData(), channelMaps.getUnchecked(i), samplesToDo);
|
||||
|
||||
bufferSize -= samplesToDo;
|
||||
offset += samplesToDo;
|
||||
|
|
@ -424,31 +413,7 @@ public:
|
|||
const int samplesToDo = jmin (bufferSize, (int) numSamplesAvailable);
|
||||
|
||||
for (int i = 0; i < numDestBuffers; ++i)
|
||||
{
|
||||
float* const dest = destBuffers[i] + offset;
|
||||
const int srcChan = channelMaps.getUnchecked(i);
|
||||
|
||||
switch (dataFormat)
|
||||
{
|
||||
case AudioDataConverters::float32LE:
|
||||
AudioDataConverters::convertFloat32LEToFloat (inputData + 4 * srcChan, dest, samplesToDo, 4 * actualNumChannels);
|
||||
break;
|
||||
|
||||
case AudioDataConverters::int32LE:
|
||||
AudioDataConverters::convertInt32LEToFloat (inputData + 4 * srcChan, dest, samplesToDo, 4 * actualNumChannels);
|
||||
break;
|
||||
|
||||
case AudioDataConverters::int24LE:
|
||||
AudioDataConverters::convertInt24LEToFloat (inputData + 3 * srcChan, dest, samplesToDo, 3 * actualNumChannels);
|
||||
break;
|
||||
|
||||
case AudioDataConverters::int16LE:
|
||||
AudioDataConverters::convertInt16LEToFloat (inputData + 2 * srcChan, dest, samplesToDo, 2 * actualNumChannels);
|
||||
break;
|
||||
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
converter->convertSamples (destBuffers[i], offset, inputData, channelMaps.getUnchecked(i), samplesToDo);
|
||||
|
||||
bufferSize -= samplesToDo;
|
||||
offset += samplesToDo;
|
||||
|
|
@ -469,6 +434,7 @@ public:
|
|||
ComSmartPtr <IAudioCaptureClient> captureClient;
|
||||
MemoryBlock reservoir;
|
||||
int reservoirSize, reservoirCapacity;
|
||||
ScopedPointer <AudioData::Converter> converter;
|
||||
|
||||
private:
|
||||
WASAPIInputDevice (const WASAPIInputDevice&);
|
||||
|
|
@ -501,6 +467,20 @@ public:
|
|||
renderClient = 0;
|
||||
}
|
||||
|
||||
void updateFormat (bool isFloat)
|
||||
{
|
||||
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> NativeType;
|
||||
|
||||
if (isFloat)
|
||||
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Float32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
|
||||
else if (bytesPerSample == 4)
|
||||
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Int32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
|
||||
else if (bytesPerSample == 3)
|
||||
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Int24, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
|
||||
else
|
||||
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
|
||||
}
|
||||
|
||||
void copyBuffers (const float** const srcBuffers, const int numSrcBuffers, int bufferSize, Thread& thread)
|
||||
{
|
||||
if (numChannels <= 0)
|
||||
|
|
@ -530,31 +510,7 @@ public:
|
|||
if (OK (renderClient->GetBuffer (samplesToDo, &outputData)))
|
||||
{
|
||||
for (int i = 0; i < numSrcBuffers; ++i)
|
||||
{
|
||||
const float* const source = srcBuffers[i] + offset;
|
||||
const int destChan = channelMaps.getUnchecked(i);
|
||||
|
||||
switch (dataFormat)
|
||||
{
|
||||
case AudioDataConverters::float32LE:
|
||||
AudioDataConverters::convertFloatToFloat32LE (source, outputData + 4 * destChan, samplesToDo, 4 * actualNumChannels);
|
||||
break;
|
||||
|
||||
case AudioDataConverters::int32LE:
|
||||
AudioDataConverters::convertFloatToInt32LE (source, outputData + 4 * destChan, samplesToDo, 4 * actualNumChannels);
|
||||
break;
|
||||
|
||||
case AudioDataConverters::int24LE:
|
||||
AudioDataConverters::convertFloatToInt24LE (source, outputData + 3 * destChan, samplesToDo, 3 * actualNumChannels);
|
||||
break;
|
||||
|
||||
case AudioDataConverters::int16LE:
|
||||
AudioDataConverters::convertFloatToInt16LE (source, outputData + 2 * destChan, samplesToDo, 2 * actualNumChannels);
|
||||
break;
|
||||
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
converter->convertSamples (outputData, channelMaps.getUnchecked(i), srcBuffers[i], offset, samplesToDo);
|
||||
|
||||
renderClient->ReleaseBuffer (samplesToDo, 0);
|
||||
|
||||
|
|
@ -565,6 +521,7 @@ public:
|
|||
}
|
||||
|
||||
ComSmartPtr <IAudioRenderClient> renderClient;
|
||||
ScopedPointer <AudioData::Converter> converter;
|
||||
|
||||
private:
|
||||
WASAPIOutputDevice (const WASAPIOutputDevice&);
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ namespace NumberToStringConverters
|
|||
|
||||
static juce_wchar getDecimalPoint()
|
||||
{
|
||||
#if JUCE_WINDOWS && _MSC_VER < 1400
|
||||
#if JUCE_MSVC && _MSC_VER < 1400
|
||||
static juce_wchar dp = std::_USE (std::locale(), std::numpunct <wchar_t>).decimal_point();
|
||||
#else
|
||||
static juce_wchar dp = std::use_facet <std::numpunct <wchar_t> > (std::locale()).decimal_point();
|
||||
|
|
@ -387,7 +387,7 @@ namespace NumberToStringConverters
|
|||
else
|
||||
{
|
||||
#if JUCE_WINDOWS
|
||||
#if _MSC_VER <= 1400
|
||||
#if JUCE_MSVC && _MSC_VER <= 1400
|
||||
len = _snwprintf (buffer, numChars, L"%.9g", n);
|
||||
#else
|
||||
len = _snwprintf_s (buffer, numChars, _TRUNCATE, L"%.9g", n);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue