Browse Source

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.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
ba62157841
27 changed files with 1579 additions and 2486 deletions
  1. +3
    -1
      extras/audio plugins/wrapper/juce_IncludeCharacteristics.h
  2. +24
    -5
      extras/juce demo/Source/demos/AudioDemoPlaybackPage.cpp
  3. +1
    -0
      extras/juce demo/Source/demos/AudioDemoPlaybackPage.h
  4. +3
    -3
      juce_Config.h
  5. +349
    -960
      juce_amalgamated.cpp
  6. +667
    -523
      juce_amalgamated.h
  7. +90
    -471
      src/audio/audio_file_formats/juce_AiffAudioFormat.cpp
  8. +27
    -0
      src/audio/audio_file_formats/juce_AudioFormatReader.h
  9. +20
    -0
      src/audio/audio_file_formats/juce_AudioFormatWriter.h
  10. +92
    -343
      src/audio/audio_file_formats/juce_WavAudioFormat.cpp
  11. +15
    -6
      src/audio/dsp/juce_AudioDataConverters.cpp
  12. +119
    -29
      src/audio/dsp/juce_AudioDataConverters.h
  13. +7
    -3
      src/audio/processors/juce_AudioProcessor.h
  14. +6
    -0
      src/containers/juce_HeapBlock.h
  15. +7
    -0
      src/containers/juce_Variant.cpp
  16. +1
    -1
      src/core/juce_StandardHeader.h
  17. +1
    -1
      src/gui/components/controls/juce_ListBox.h
  18. +82
    -45
      src/native/linux/juce_linux_Audio.cpp
  19. +13
    -4
      src/native/mac/juce_mac_AudioCDBurner.mm
  20. +0
    -1
      src/native/mac/juce_mac_CoreAudio.cpp
  21. +1
    -1
      src/native/mac/juce_mac_Fonts.mm
  22. +1
    -1
      src/native/mac/juce_mac_MessageManager.mm
  23. +9
    -4
      src/native/windows/juce_win32_AudioCDReader.cpp
  24. +1
    -1
      src/native/windows/juce_win32_DynamicLibraryLoader.cpp
  25. +1
    -1
      src/native/windows/juce_win32_Threads.cpp
  26. +37
    -80
      src/native/windows/juce_win32_WASAPI.cpp
  27. +2
    -2
      src/text/juce_String.cpp

+ 3
- 1
extras/audio plugins/wrapper/juce_IncludeCharacteristics.h View File

@@ -36,7 +36,9 @@
*/ */
#include "JucePluginCharacteristics.h" #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 // The following stuff is just to cause a compile error if you've forgotten to


+ 24
- 5
extras/juce demo/Source/demos/AudioDemoPlaybackPage.cpp View File

@@ -27,7 +27,8 @@
//[MiscUserDefs] You can add your own user definitions and misc code here... //[MiscUserDefs] You can add your own user definitions and misc code here...
class DemoThumbnailComp : public Component, class DemoThumbnailComp : public Component,
public ChangeListener
public ChangeListener,
public FileDragAndDropTarget
{ {
public: public:
DemoThumbnailComp() DemoThumbnailComp()
@@ -104,6 +105,19 @@ public:
repaint(); 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; AudioFormatManager formatManager;
AudioThumbnailCache thumbnailCache; AudioThumbnailCache thumbnailCache;
AudioThumbnail thumbnail; 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... //[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) void AudioDemoPlaybackPage::loadFileIntoTransport (const File& audioFile)
{ {
// unload the previous file source and delete it.. // unload the previous file source and delete it..
@@ -292,10 +314,7 @@ void AudioDemoPlaybackPage::loadFileIntoTransport (const File& audioFile)
void AudioDemoPlaybackPage::selectionChanged() 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&) void AudioDemoPlaybackPage::fileClicked (const File&, const MouseEvent&)


+ 1
- 0
extras/juce demo/Source/demos/AudioDemoPlaybackPage.h View File

@@ -54,6 +54,7 @@ public:
void selectionChanged(); void selectionChanged();
void fileClicked (const File& file, const MouseEvent& e); void fileClicked (const File& file, const MouseEvent& e);
void fileDoubleClicked (const File& file); void fileDoubleClicked (const File& file);
void showFile (const File& file);
//[/UserMethods] //[/UserMethods]
void paint (Graphics& g); void paint (Graphics& g);


+ 3
- 3
juce_Config.h View File

@@ -147,7 +147,7 @@
reduce code size. reduce code size.
*/ */
#if (! defined (JUCE_USE_CDBURNER)) && ! (JUCE_WINDOWS && ! JUCE_MSVC) #if (! defined (JUCE_USE_CDBURNER)) && ! (JUCE_WINDOWS && ! JUCE_MSVC)
#define JUCE_USE_CDBURNER 0
#define JUCE_USE_CDBURNER 1
#endif #endif
/** JUCE_USE_CDREADER: Enables the audio CD reader code (Mac and Windows only). /** JUCE_USE_CDREADER: Enables the audio CD reader code (Mac and Windows only).
@@ -155,7 +155,7 @@
reduce code size. reduce code size.
*/ */
#ifndef JUCE_USE_CDREADER #ifndef JUCE_USE_CDREADER
#define JUCE_USE_CDREADER 0
#define JUCE_USE_CDREADER 1
#endif #endif
//============================================================================= //=============================================================================
@@ -244,7 +244,7 @@
Carbon isn't required for a normal app, but may be needed by specialised classes like Carbon isn't required for a normal app, but may be needed by specialised classes like
plugin-hosts, which support older APIs. plugin-hosts, which support older APIs.
*/ */
#ifndef JUCE_SUPPORT_CARBON
#if ! (defined (JUCE_SUPPORT_CARBON) || defined (__LP64__))
#define JUCE_SUPPORT_CARBON 1 #define JUCE_SUPPORT_CARBON 1
#endif #endif


+ 349
- 960
juce_amalgamated.cpp
File diff suppressed because it is too large
View File


+ 667
- 523
juce_amalgamated.h
File diff suppressed because it is too large
View File


+ 90
- 471
src/audio/audio_file_formats/juce_AiffAudioFormat.cpp View File

@@ -32,6 +32,7 @@ BEGIN_JUCE_NAMESPACE
#include "../../core/juce_PlatformUtilities.h" #include "../../core/juce_PlatformUtilities.h"
#include "../../text/juce_LocalisedStrings.h" #include "../../text/juce_LocalisedStrings.h"
//============================================================================== //==============================================================================
static const char* const aiffFormatName = "AIFF file"; static const char* const aiffFormatName = "AIFF file";
static const char* const aiffExtensions[] = { ".aiff", ".aif", 0 }; static const char* const aiffExtensions[] = { ".aiff", ".aif", 0 };
@@ -72,14 +73,14 @@ public:
hasGotVer = true; hasGotVer = true;
const int ver = input->readIntBigEndian(); const int ver = input->readIntBigEndian();
if (ver != 0 && ver != (int)0xa2805140)
if (ver != 0 && ver != (int) 0xa2805140)
break; break;
} }
else if (type == chunkName ("COMM")) else if (type == chunkName ("COMM"))
{ {
hasGotType = true; hasGotType = true;
numChannels = (unsigned int)input->readShortBigEndian();
numChannels = (unsigned int) input->readShortBigEndian();
lengthInSamples = input->readIntBigEndian(); lengthInSamples = input->readIntBigEndian();
bitsPerSample = input->readShortBigEndian(); bitsPerSample = input->readShortBigEndian();
bytesPerFrame = (numChannels * bitsPerSample) >> 3; bytesPerFrame = (numChannels * bitsPerSample) >> 3;
@@ -167,318 +168,42 @@ public:
input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame); input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame);
const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
char tempBuffer [tempBufSize];
while (numSamples > 0) 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 numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples);
const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame); const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame);
if (bytesRead < numThisTime * bytesPerFrame) if (bytesRead < numThisTime * bytesPerFrame)
zeromem (tempBuffer + bytesRead, numThisTime * bytesPerFrame - bytesRead);
if (bitsPerSample == 16)
{ {
if (littleEndian)
{
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;
}
}
}
jassert (bytesRead >= 0);
zeromem (tempBuffer + bytesRead, numThisTime * bytesPerFrame - bytesRead);
} }
else if (bitsPerSample == 24)
{
const char* src = tempBuffer;
if (littleEndian)
{
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);
jassert (! usesFloatingPointData); // (would need to add support for this if it's possible)
if (littleEndian)
if (littleEndian)
{
switch (bitsPerSample)
{ {
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++);
}
}
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 (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)
else
{ {
const char* src = tempBuffer;
if (numChannels > 1)
switch (bitsPerSample)
{ {
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; numSamples -= numThisTime;
} }
if (numSamples > 0)
{
for (int i = numDestChannels; --i >= 0;)
if (destSamples[i] != 0)
zeromem (destSamples[i] + startOffsetInDestBuffer,
sizeof (int) * numSamples);
}
return true; return true;
} }
@@ -509,6 +226,68 @@ private:
//============================================================================== //==============================================================================
class AiffAudioFormatWriter : public AudioFormatWriter 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; MemoryBlock tempBlock;
uint32 lengthInSamples, bytesWritten; uint32 lengthInSamples, bytesWritten;
int64 headerPosition; int64 headerPosition;
@@ -592,153 +371,6 @@ class AiffAudioFormatWriter : public AudioFormatWriter
jassert (output->getPosition() == headerLen); 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); 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 #if JUCE_MAC
bool AiffAudioFormat::canHandleFile (const File& f) bool AiffAudioFormat::canHandleFile (const File& f)
@@ -785,8 +410,7 @@ bool AiffAudioFormat::canHandleFile (const File& f)
} }
#endif #endif
AudioFormatReader* AiffAudioFormat::createReaderFor (InputStream* sourceStream,
const bool deleteStreamIfOpeningFails)
AudioFormatReader* AiffAudioFormat::createReaderFor (InputStream* sourceStream, const bool deleteStreamIfOpeningFails)
{ {
ScopedPointer <AiffAudioFormatReader> w (new AiffAudioFormatReader (sourceStream)); ScopedPointer <AiffAudioFormatReader> w (new AiffAudioFormatReader (sourceStream));
@@ -801,18 +425,13 @@ AudioFormatReader* AiffAudioFormat::createReaderFor (InputStream* sourceStream,
AudioFormatWriter* AiffAudioFormat::createWriterFor (OutputStream* out, AudioFormatWriter* AiffAudioFormat::createWriterFor (OutputStream* out,
double sampleRate, double sampleRate,
unsigned int chans,
unsigned int numberOfChannels,
int bitsPerSample, int bitsPerSample,
const StringPairArray& /*metadataValues*/, const StringPairArray& /*metadataValues*/,
int /*qualityOptionIndex*/) int /*qualityOptionIndex*/)
{ {
if (getPossibleBitDepths().contains (bitsPerSample)) if (getPossibleBitDepths().contains (bitsPerSample))
{
return new AiffAudioFormatWriter (out,
sampleRate,
chans,
bitsPerSample);
}
return new AiffAudioFormatWriter (out, sampleRate, numberOfChannels, bitsPerSample);
return 0; return 0;
} }


+ 27
- 0
src/audio/audio_file_formats/juce_AudioFormatReader.h View File

@@ -28,6 +28,7 @@
#include "../../io/streams/juce_InputStream.h" #include "../../io/streams/juce_InputStream.h"
#include "../../text/juce_StringPairArray.h" #include "../../text/juce_StringPairArray.h"
#include "../dsp/juce_AudioDataConverters.h"
class AudioFormat; class AudioFormat;
@@ -218,6 +219,32 @@ public:
//============================================================================== //==============================================================================
juce_UseDebuggingNewOperator 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: private:
String formatName; String formatName;


+ 20
- 0
src/audio/audio_file_formats/juce_AudioFormatWriter.h View File

@@ -160,6 +160,26 @@ protected:
/** The output stream for Use by subclasses. */ /** The output stream for Use by subclasses. */
OutputStream* output; 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: private:
String formatName; String formatName;


+ 92
- 343
src/audio/audio_file_formats/juce_WavAudioFormat.cpp View File

@@ -38,7 +38,6 @@ BEGIN_JUCE_NAMESPACE
static const char* const wavFormatName = "WAV file"; static const char* const wavFormatName = "WAV file";
static const char* const wavExtensions[] = { ".wav", ".bwf", 0 }; static const char* const wavExtensions[] = { ".wav", ".bwf", 0 };
//============================================================================== //==============================================================================
const char* const WavAudioFormat::bwavDescription = "bwav description"; const char* const WavAudioFormat::bwavDescription = "bwav description";
const char* const WavAudioFormat::bwavOriginator = "bwav originator"; const char* const WavAudioFormat::bwavOriginator = "bwav originator";
@@ -258,17 +257,7 @@ struct ExtensibleWavSubFormat
//============================================================================== //==============================================================================
class WavAudioFormatReader : public AudioFormatReader 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: public:
int64 bwavChunkStart, bwavSize;
//============================================================================== //==============================================================================
WavAudioFormatReader (InputStream* const in) WavAudioFormatReader (InputStream* const in)
: AudioFormatReader (in, TRANS (wavFormatName)), : AudioFormatReader (in, TRANS (wavFormatName)),
@@ -389,6 +378,7 @@ public:
bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples) int64 startSampleInFile, int numSamples)
{ {
jassert (destSamples != 0);
const int64 samplesAvailable = lengthInSamples - startSampleInFile; const int64 samplesAvailable = lengthInSamples - startSampleInFile;
if (samplesAvailable < numSamples) if (samplesAvailable < numSamples)
@@ -405,267 +395,55 @@ public:
input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame); input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame);
const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
char tempBuffer [tempBufSize];
while (numSamples > 0) 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 numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples);
const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame); const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame);
if (bytesRead < numThisTime * bytesPerFrame) if (bytesRead < numThisTime * bytesPerFrame)
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;
}
}
jassert (bytesRead >= 0);
zeromem (tempBuffer + bytesRead, numThisTime * bytesPerFrame - bytesRead);
} }
else if (bitsPerSample == 24)
{
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)
switch (bitsPerSample)
{ {
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; startOffsetInDestBuffer += numThisTime;
numSamples -= 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; return true;
} }
int64 bwavChunkStart, bwavSize;
juce_UseDebuggingNewOperator juce_UseDebuggingNewOperator
};
//==============================================================================
class WavAudioFormatWriter : public AudioFormatWriter
{
MemoryBlock tempBlock, bwavChunk, smplChunk;
uint32 lengthInSamples, bytesWritten;
int64 headerPosition;
bool writeFailed;
private:
ScopedPointer<AudioData::Converter> converter;
int bytesPerFrame;
int64 dataChunkStart, dataLength;
static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); } 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);
(void) seekedOk;
// if this fails, you've given it an output stream that can't seek! It needs
// to be able to seek back to write the header
jassert (seekedOk);
const int bytesPerFrame = numChannels * bitsPerSample / 8;
output->writeInt (chunkName ("RIFF"));
output->writeInt ((int) (lengthInSamples * bytesPerFrame
+ ((bwavChunk.getSize() > 0) ? (44 + bwavChunk.getSize()) : 36)));
output->writeInt (chunkName ("WAVE"));
output->writeInt (chunkName ("fmt "));
output->writeInt (16);
output->writeShort ((bitsPerSample < 32) ? (short) 1 /*WAVE_FORMAT_PCM*/
: (short) 3 /*WAVE_FORMAT_IEEE_FLOAT*/);
output->writeShort ((short) numChannels);
output->writeInt ((int) sampleRate);
output->writeInt (bytesPerFrame * (int) sampleRate);
output->writeShort ((short) bytesPerFrame);
output->writeShort ((short) bitsPerSample);
if (bwavChunk.getSize() > 0)
{
output->writeInt (chunkName ("bext"));
output->writeInt ((int) bwavChunk.getSize());
output->write (bwavChunk.getData(), (int) bwavChunk.getSize());
}
if (smplChunk.getSize() > 0)
{
output->writeInt (chunkName ("smpl"));
output->writeInt ((int) smplChunk.getSize());
output->write (smplChunk.getData(), (int) smplChunk.getSize());
}
output->writeInt (chunkName ("data"));
output->writeInt (lengthInSamples * bytesPerFrame);
usesFloatingPointData = (bitsPerSample == 32);
}
WavAudioFormatReader (const WavAudioFormatReader&);
WavAudioFormatReader& operator= (const WavAudioFormatReader&);
};
//==============================================================================
class WavAudioFormatWriter : public AudioFormatWriter
{
public: public:
//============================================================================== //==============================================================================
WavAudioFormatWriter (OutputStream* const out, WavAudioFormatWriter (OutputStream* const out,
@@ -700,104 +478,25 @@ public:
//============================================================================== //==============================================================================
bool write (const int** data, int numSamples) bool write (const int** data, int numSamples)
{ {
jassert (data != 0 && *data != 0); // the input must contain at least one channel!
if (writeFailed) if (writeFailed)
return false; return false;
const int bytes = numChannels * numSamples * bitsPerSample / 8; const int bytes = numChannels * numSamples * bitsPerSample / 8;
tempBlock.ensureSize (bytes, false); 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)
switch (bitsPerSample)
{ {
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));
}
}
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 if (bytesWritten + bytes >= (uint32) 0xfff00000
|| ! output->write (buffer, bytes))
|| ! output->write (tempBlock.getData(), bytes))
{ {
// failed to write to disk, so let's try writing the header. // 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 // If it's just run out of disk space, then if it does manage
@@ -816,6 +515,63 @@ public:
} }
juce_UseDebuggingNewOperator juce_UseDebuggingNewOperator
private:
ScopedPointer<AudioData::Converter> converter;
MemoryBlock tempBlock, bwavChunk, smplChunk;
uint32 lengthInSamples, bytesWritten;
int64 headerPosition;
bool writeFailed;
static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
void writeHeader()
{
const bool seekedOk = output->setPosition (headerPosition);
(void) seekedOk;
// if this fails, you've given it an output stream that can't seek! It needs
// to be able to seek back to write the header
jassert (seekedOk);
const int bytesPerFrame = numChannels * bitsPerSample / 8;
output->writeInt (chunkName ("RIFF"));
output->writeInt ((int) (lengthInSamples * bytesPerFrame
+ ((bwavChunk.getSize() > 0) ? (44 + bwavChunk.getSize()) : 36)));
output->writeInt (chunkName ("WAVE"));
output->writeInt (chunkName ("fmt "));
output->writeInt (16);
output->writeShort ((bitsPerSample < 32) ? (short) 1 /*WAVE_FORMAT_PCM*/
: (short) 3 /*WAVE_FORMAT_IEEE_FLOAT*/);
output->writeShort ((short) numChannels);
output->writeInt ((int) sampleRate);
output->writeInt (bytesPerFrame * (int) sampleRate);
output->writeShort ((short) bytesPerFrame);
output->writeShort ((short) bitsPerSample);
if (bwavChunk.getSize() > 0)
{
output->writeInt (chunkName ("bext"));
output->writeInt ((int) bwavChunk.getSize());
output->write (bwavChunk.getData(), (int) bwavChunk.getSize());
}
if (smplChunk.getSize() > 0)
{
output->writeInt (chunkName ("smpl"));
output->writeInt ((int) smplChunk.getSize());
output->write (smplChunk.getData(), (int) smplChunk.getSize());
}
output->writeInt (chunkName ("data"));
output->writeInt (lengthInSamples * bytesPerFrame);
usesFloatingPointData = (bitsPerSample == 32);
}
WavAudioFormatWriter (const WavAudioFormatWriter&);
WavAudioFormatWriter& operator= (const WavAudioFormatWriter&);
}; };
//============================================================================== //==============================================================================
@@ -840,15 +596,8 @@ const Array <int> WavAudioFormat::getPossibleBitDepths()
return Array <int> (depths); 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, AudioFormatReader* WavAudioFormat::createReaderFor (InputStream* sourceStream,
const bool deleteStreamIfOpeningFails) const bool deleteStreamIfOpeningFails)


+ 15
- 6
src/audio/dsp/juce_AudioDataConverters.cpp View File

@@ -531,7 +531,7 @@ void AudioDataConverters::deinterleaveSamples (const float* const source,
} }
} }
/*
#if JUCE_UNIT_TESTS #if JUCE_UNIT_TESTS
#include "../../utilities/juce_UnitTest.h" #include "../../utilities/juce_UnitTest.h"
@@ -546,6 +546,12 @@ public:
struct Test5 struct Test5
{ {
static void test (UnitTest& unitTest) static void test (UnitTest& unitTest)
{
test (unitTest, false);
test (unitTest, true);
}
static void test (UnitTest& unitTest, bool inPlace)
{ {
const int numSamples = 2048; const int numSamples = 2048;
int32 original [numSamples], converted [numSamples], reversed [numSamples]; int32 original [numSamples], converted [numSamples], reversed [numSamples];
@@ -572,13 +578,15 @@ public:
// convert data from the source to dest format.. // convert data from the source to dest format..
ScopedPointer<AudioData::Converter> conv (new AudioData::ConverterInstance <AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>, ScopedPointer<AudioData::Converter> conv (new AudioData::ConverterInstance <AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>,
AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::NonConst> >()); AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::NonConst> >());
conv->convertSamples (converted, original, numSamples);
conv->convertSamples (inPlace ? reversed : converted, original, numSamples);
// ..and back again.. // ..and back again..
conv = new AudioData::ConverterInstance <AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>, conv = new AudioData::ConverterInstance <AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>,
AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst> >(); 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; int biggestDiff = 0;
@@ -615,11 +623,12 @@ public:
{ {
static void test (UnitTest& unitTest) 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::Int16>::test (unitTest);
Test3 <FormatType, Endianness, AudioData::Int24>::test (unitTest); Test3 <FormatType, Endianness, AudioData::Int24>::test (unitTest);
Test3 <FormatType, Endianness, AudioData::Int32>::test (unitTest); Test3 <FormatType, Endianness, AudioData::Int32>::test (unitTest);
Test3 <FormatType, Endianness, AudioData::Float32>::test (unitTest); Test3 <FormatType, Endianness, AudioData::Float32>::test (unitTest);
Test3 <FormatType, Endianness, AudioData::Int8>::test (unitTest);
} }
}; };
@@ -648,6 +657,6 @@ public:
static AudioConversionTests audioConversionUnitTests; static AudioConversionTests audioConversionUnitTests;
#endif #endif
*/
END_JUCE_NAMESPACE END_JUCE_NAMESPACE

+ 119
- 29
src/audio/dsp/juce_AudioDataConverters.h View File

@@ -26,7 +26,6 @@
#ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ #ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__
#define __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. // 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 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 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 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. */ 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), : InterleavingType (numInterleavedChannels),
data (Constness::toVoidPtr (sourceData)) 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. */ /** Creates a copy of another pointer. */
Pointer (const Pointer& other) throw() Pointer (const Pointer& other) throw()
: data (other.data)
: InterleavingType (other),
data (other.data)
{ {
} }
Pointer& operator= (const Pointer& other) throw() Pointer& operator= (const Pointer& other) throw()
{ {
data = other.data; data = other.data;
InterleavingType::copyFrom (other);
return *this; return *this;
} }
@@ -172,9 +171,12 @@ public:
Endianness::setAsInt32 (data, newValue); 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; } 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. */ /** Adds a number of samples to the pointer's position. */
Pointer& operator+= (int samplesToJump) throw() { advanceDataBy (data, samplesToJump); return *this; } 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! static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead!
Pointer dest (*this); 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. */ /** Returns true if the pointer is using a floating-point format. */
@@ -217,9 +238,15 @@ public:
/** Returns true if the format is big-endian. */ /** Returns true if the format is big-endian. */
static bool isBigEndian() throw() { return (bool) Endianness::isBigEndian; } 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. */ /** Returns the number of interleaved channels in the format. */
int getNumInterleavedChannels() const throw() { return (int) this->numInterleavedChannels; } 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. /** 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 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, 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; } static int get32BitResolution() throw() { return (int) SampleFormat::resolution; }
/** Returns a pointer to the underlying data. */
const void* getRawData() const throw() { return data.data; }
private: private:
//============================================================================== //==============================================================================
SampleFormat data; SampleFormat data;
@@ -248,9 +278,15 @@ public:
public: public:
virtual ~Converter() {} 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 class ConverterInstance : public Converter
{ {
public: public:
ConverterInstance() {}
ConverterInstance (int numSourceChannels = 1, int numDestChannels = 1)
: sourceChannels (numSourceChannels), destChannels (numDestChannels)
{}
~ConverterInstance() {} ~ConverterInstance() {}
void convertSamples (void* dest, const void* source, int numSamples) const 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); d.convertSamples (s, numSamples);
} }
private: private:
ConverterInstance (const ConverterInstance&); ConverterInstance (const ConverterInstance&);
ConverterInstance& operator= (const ConverterInstance&); ConverterInstance& operator= (const ConverterInstance&);
const int sourceChannels, destChannels;
}; };
}; };
@@ -324,18 +375,45 @@ public:
inline void skip (int numSamples) throw() { data += numSamples; } inline void skip (int numSamples) throw() { data += numSamples; }
inline float getAsFloatLE() const throw() { return (float) (*data * (1.0 / (1.0 + maxValue))); } inline float getAsFloatLE() const throw() { return (float) (*data * (1.0 / (1.0 + maxValue))); }
inline float getAsFloatBE() const throw() { return getAsFloatLE(); } 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 void setAsFloatBE (float newValue) throw() { setAsFloatLE (newValue); }
inline int32 getAsInt32LE() const throw() { return (int) (*data << 24); } inline int32 getAsInt32LE() const throw() { return (int) (*data << 24); }
inline int32 getAsInt32BE() const throw() { return getAsInt32LE(); } inline int32 getAsInt32BE() const throw() { return getAsInt32LE(); }
inline void setAsInt32LE (int newValue) throw() { *data = (int8) (newValue >> 24); } inline void setAsInt32LE (int newValue) throw() { *data = (int8) (newValue >> 24); }
inline void setAsInt32BE (int newValue) throw() { setAsInt32LE (newValue); } 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 copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); }
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); }
inline void copyFromSameType (Int8& source) throw() { *data = *source.data; } inline void copyFromSameType (Int8& source) throw() { *data = *source.data; }
int8* 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 class AudioData::Int16
@@ -353,12 +431,14 @@ public:
inline int32 getAsInt32BE() const throw() { return (int32) (ByteOrder::swapIfLittleEndian ((uint16) *data) << 16); } 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 setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) (newValue >> 16)); }
inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((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 copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); }
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); }
inline void copyFromSameType (Int16& source) throw() { *data = *source.data; } inline void copyFromSameType (Int16& source) throw() { *data = *source.data; }
uint16* data; uint16* data;
enum { maxValue = 0x7fff, resolution = (1 << 16), isFloat = 0 };
enum { bytesPerSample = 2, maxValue = 0x7fff, resolution = (1 << 16), isFloat = 0 };
}; };
class AudioData::Int24 class AudioData::Int24
@@ -376,12 +456,14 @@ public:
inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::bigEndian24Bit (data) << 8; } inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::bigEndian24Bit (data) << 8; }
inline void setAsInt32LE (int32 newValue) throw() { ByteOrder::littleEndian24BitToChars (newValue >> 8, data); } inline void setAsInt32LE (int32 newValue) throw() { ByteOrder::littleEndian24BitToChars (newValue >> 8, data); }
inline void setAsInt32BE (int32 newValue) throw() { ByteOrder::bigEndian24BitToChars (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 copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); }
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (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]; } inline void copyFromSameType (Int24& source) throw() { data[0] = source.data[0]; data[1] = source.data[1]; data[2] = source.data[2]; }
char* data; char* data;
enum { maxValue = 0x7fffff, resolution = (1 << 8), isFloat = 0 };
enum { bytesPerSample = 3, maxValue = 0x7fffff, resolution = (1 << 8), isFloat = 0 };
}; };
class AudioData::Int32 class AudioData::Int32
@@ -399,12 +481,14 @@ public:
inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::swapIfLittleEndian (*data); } inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::swapIfLittleEndian (*data); }
inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); } inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); }
inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((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 copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); }
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); }
inline void copyFromSameType (Int32& source) throw() { *data = *source.data; } inline void copyFromSameType (Int32& source) throw() { *data = *source.data; }
uint32* data; uint32* data;
enum { maxValue = 0x7fffffff, resolution = 1, isFloat = 0 };
enum { bytesPerSample = 4, maxValue = 0x7fffffff, resolution = 1, isFloat = 0 };
}; };
class AudioData::Float32 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 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 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 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 copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); }
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsFloatBE (source.getAsFloat()); } template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsFloatBE (source.getAsFloat()); }
inline void copyFromSameType (Float32& source) throw() { *data = *source.data; } inline void copyFromSameType (Float32& source) throw() { *data = *source.data; }
float* 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: public:
inline NonInterleaved() throw() {} inline NonInterleaved() throw() {}
inline NonInterleaved (const NonInterleaved&) throw() {}
inline NonInterleaved (const int) 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 }; enum { isInterleavedType = 0, numInterleavedChannels = 1 };
}; };
@@ -452,14 +543,15 @@ class AudioData::Interleaved
{ {
public: public:
inline Interleaved() throw() : numInterleavedChannels (1) {} inline Interleaved() throw() : numInterleavedChannels (1) {}
inline Interleaved (const Interleaved& other) throw() : numInterleavedChannels (other.numInterleavedChannels) {}
inline Interleaved (const int numInterleavedChannels_) throw() : numInterleavedChannels (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 advanceData (SampleFormatType& s) throw() { s.skip (numInterleavedChannels); }
template <class SampleFormatType> inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numInterleavedChannels * numSamples); } 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 }; enum { isInterleavedType = 1 };
private:
Interleaved& operator= (const Interleaved&);
}; };
//============================================================================== //==============================================================================
@@ -481,8 +573,6 @@ public:
#endif #endif
#endif
//============================================================================== //==============================================================================
/** /**
A set of routines to convert buffers of 32-bit floating point data to and from A set of routines to convert buffers of 32-bit floating point data to and from


+ 7
- 3
src/audio/processors/juce_AudioProcessor.h View File

@@ -528,13 +528,17 @@ public:
/** Removes a previously added listener. */ /** Removes a previously added listener. */
void removeListener (AudioProcessorListener* listenerToRemove); 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. */ /** Not for public use - this is called before deleting an editor component. */
void editorBeingDeleted (AudioProcessorEditor* editor) throw(); 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. */ /** Not for public use - this is called to initialise the processor before playing. */
void setPlayConfigDetails (int numIns, int numOuts, void setPlayConfigDetails (int numIns, int numOuts,
double sampleRate, double sampleRate,


+ 6
- 0
src/containers/juce_HeapBlock.h View File

@@ -122,6 +122,12 @@ public:
*/ */
inline operator void*() const throw() { return static_cast <void*> (data); } 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. /** 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 Obviously this will cause problems if the array hasn't been initialised, because it'll
be referencing a null pointer. be referencing a null pointer.


+ 7
- 0
src/containers/juce_Variant.cpp View File

@@ -63,6 +63,7 @@ public:
class var::VariantType_Void : public var::VariantType class var::VariantType_Void : public var::VariantType
{ {
public: public:
VariantType_Void() {}
static const VariantType_Void* getInstance() { static const VariantType_Void i; return &i; } static const VariantType_Void* getInstance() { static const VariantType_Void i; return &i; }
bool isVoid() const throw() { return true; } bool isVoid() const throw() { return true; }
@@ -74,6 +75,7 @@ public:
class var::VariantType_Int : public var::VariantType class var::VariantType_Int : public var::VariantType
{ {
public: public:
VariantType_Int() {}
static const VariantType_Int* getInstance() { static const VariantType_Int i; return &i; } static const VariantType_Int* getInstance() { static const VariantType_Int i; return &i; }
int toInt (const ValueUnion& data) const { return data.intValue; }; int toInt (const ValueUnion& data) const { return data.intValue; };
@@ -100,6 +102,7 @@ public:
class var::VariantType_Double : public var::VariantType class var::VariantType_Double : public var::VariantType
{ {
public: public:
VariantType_Double() {}
static const VariantType_Double* getInstance() { static const VariantType_Double i; return &i; } static const VariantType_Double* getInstance() { static const VariantType_Double i; return &i; }
int toInt (const ValueUnion& data) const { return (int) data.doubleValue; }; int toInt (const ValueUnion& data) const { return (int) data.doubleValue; };
@@ -126,6 +129,7 @@ public:
class var::VariantType_Bool : public var::VariantType class var::VariantType_Bool : public var::VariantType
{ {
public: public:
VariantType_Bool() {}
static const VariantType_Bool* getInstance() { static const VariantType_Bool i; return &i; } static const VariantType_Bool* getInstance() { static const VariantType_Bool i; return &i; }
int toInt (const ValueUnion& data) const { return data.boolValue ? 1 : 0; }; int toInt (const ValueUnion& data) const { return data.boolValue ? 1 : 0; };
@@ -151,6 +155,7 @@ public:
class var::VariantType_String : public var::VariantType class var::VariantType_String : public var::VariantType
{ {
public: public:
VariantType_String() {}
static const VariantType_String* getInstance() { static const VariantType_String i; return &i; } static const VariantType_String* getInstance() { static const VariantType_String i; return &i; }
void cleanUp (ValueUnion& data) const throw() { delete data.stringValue; } void cleanUp (ValueUnion& data) const throw() { delete data.stringValue; }
@@ -185,6 +190,7 @@ public:
class var::VariantType_Object : public var::VariantType class var::VariantType_Object : public var::VariantType
{ {
public: public:
VariantType_Object() {}
static const VariantType_Object* getInstance() { static const VariantType_Object i; return &i; } 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(); } 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 class var::VariantType_Method : public var::VariantType
{ {
public: public:
VariantType_Method() {}
static const VariantType_Method* getInstance() { static const VariantType_Method i; return &i; } static const VariantType_Method* getInstance() { static const VariantType_Method i; return &i; }
const String toString (const ValueUnion&) const { return "Method"; } const String toString (const ValueUnion&) const { return "Method"; }


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

@@ -33,7 +33,7 @@
*/ */
#define JUCE_MAJOR_VERSION 1 #define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52 #define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 69
#define JUCE_BUILDNUMBER 70
/** Current Juce version number. /** Current Juce version number.


+ 1
- 1
src/gui/components/controls/juce_ListBox.h View File

@@ -525,7 +525,7 @@ public:
@see Component::createComponentSnapshot @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. /** Returns the viewport that this ListBox uses.


+ 82
- 45
src/native/linux/juce_linux_Audio.cpp View File

@@ -82,7 +82,7 @@ static void getDeviceProperties (const String& deviceID,
if (snd_ctl_pcm_info (handle, info) >= 0) if (snd_ctl_pcm_info (handle, info) >= 0)
{ {
snd_pcm_t* pcmHandle; 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); getDeviceNumChannels (pcmHandle, &minChansOut, &maxChansOut);
getDeviceSampleRates (pcmHandle, rates); getDeviceSampleRates (pcmHandle, rates);
@@ -96,7 +96,7 @@ static void getDeviceProperties (const String& deviceID,
if (snd_ctl_pcm_info (handle, info) >= 0) if (snd_ctl_pcm_info (handle, info) >= 0)
{ {
snd_pcm_t* pcmHandle; 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); getDeviceNumChannels (pcmHandle, &minChansIn, &maxChansIn);
@@ -115,14 +115,12 @@ static void getDeviceProperties (const String& deviceID,
class ALSADevice class ALSADevice
{ {
public: public:
ALSADevice (const String& deviceID,
const bool forInput)
ALSADevice (const String& deviceID, bool forInput)
: handle (0), : handle (0),
bitDepth (16), bitDepth (16),
numChannelsRunning (0), numChannelsRunning (0),
latency (0), latency (0),
isInput (forInput),
sampleFormat (AudioDataConverters::int16LE)
isInput (forInput)
{ {
failed (snd_pcm_open (&handle, deviceID.toUTF8(), failed (snd_pcm_open (&handle, deviceID.toUTF8(),
forInput ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, forInput ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
@@ -156,22 +154,26 @@ public:
return false; 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; 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) 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; break;
} }
} }
@@ -235,48 +237,44 @@ public:
} }
//============================================================================== //==============================================================================
bool write (AudioSampleBuffer& outputChannelBuffer, const int numSamples)
bool writeToOutputDevice (AudioSampleBuffer& outputChannelBuffer, const int numSamples)
{ {
jassert (numChannelsRunning <= outputChannelBuffer.getNumChannels()); jassert (numChannelsRunning <= outputChannelBuffer.getNumChannels());
float** const data = outputChannelBuffer.getArrayOfChannels(); float** const data = outputChannelBuffer.getArrayOfChannels();
snd_pcm_sframes_t numDone = 0;
if (isInterleaved) if (isInterleaved)
{ {
scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false); 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);
snd_pcm_sframes_t num = snd_pcm_writei (handle, interleaved, numSamples);
for (int i = 0; i < numChannelsRunning; ++i)
converter->convertSamples (scratch.getData(), i, data[i], 0, numSamples);
if (failed (num) && num != -EPIPE && num != -ESTRPIPE)
return false;
numDone = snd_pcm_writei (handle, scratch.getData(), numSamples);
} }
else else
{ {
for (int i = 0; i < numChannelsRunning; ++i) 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; return false;
} }
else if (numDone != -ESTRPIPE)
return false;
} }
return true; return true;
} }
bool read (AudioSampleBuffer& inputChannelBuffer, const int numSamples)
bool readFromInputDevice (AudioSampleBuffer& inputChannelBuffer, const int numSamples)
{ {
jassert (numChannelsRunning <= inputChannelBuffer.getNumChannels()); jassert (numChannelsRunning <= inputChannelBuffer.getNumChannels());
float** const data = inputChannelBuffer.getArrayOfChannels(); float** const data = inputChannelBuffer.getArrayOfChannels();
@@ -284,9 +282,8 @@ public:
if (isInterleaved) if (isInterleaved)
{ {
scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false); 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)) if (failed (num))
{ {
@@ -299,8 +296,8 @@ public:
return false; 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 else
{ {
@@ -310,8 +307,7 @@ public:
return false; return false;
for (int i = 0; i < numChannelsRunning; ++i) 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; return true;
@@ -329,7 +325,48 @@ private:
const bool isInput; const bool isInput;
bool isInterleaved; bool isInterleaved;
MemoryBlock scratch; 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) bool failed (const int errorNum)
@@ -522,7 +559,7 @@ public:
{ {
if (inputDevice != 0) if (inputDevice != 0)
{ {
if (! inputDevice->read (inputChannelBuffer, bufferSize))
if (! inputDevice->readFromInputDevice (inputChannelBuffer, bufferSize))
{ {
DBG ("ALSA: read failure"); DBG ("ALSA: read failure");
break; break;
@@ -560,7 +597,7 @@ public:
failed (snd_pcm_avail_update (outputDevice->handle)); failed (snd_pcm_avail_update (outputDevice->handle));
if (! outputDevice->write (outputChannelBuffer, bufferSize))
if (! outputDevice->writeToOutputDevice (outputChannelBuffer, bufferSize))
{ {
DBG ("ALSA: write failure"); DBG ("ALSA: write failure");
break; break;


+ 13
- 4
src/native/mac/juce_mac_AudioCDBurner.mm View File

@@ -279,10 +279,19 @@ END_JUCE_NAMESPACE
source->getNextAudioBlock (info); 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; readPosition += numSamples;
} }


+ 0
- 1
src/native/mac/juce_mac_CoreAudio.cpp View File

@@ -306,7 +306,6 @@ public:
size = sizeof (lat); size = sizeof (lat);
pa.mSelector = kAudioDevicePropertyLatency; pa.mSelector = kAudioDevicePropertyLatency;
pa.mScope = kAudioDevicePropertyScopeInput; pa.mScope = kAudioDevicePropertyScopeInput;
//if (AudioDeviceGetProperty (deviceID, 0, true, kAudioDevicePropertyLatency, &size, &lat) == noErr)
if (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &lat) == noErr) if (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &lat) == noErr)
inputLatency = (int) lat; inputLatency = (int) lat;


+ 1
- 1
src/native/mac/juce_mac_Fonts.mm View File

@@ -458,7 +458,7 @@ private:
} }
// If we failed to find it "properly", this dodgy fall-back seems to do the trick for most fonts! // 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: private:


+ 1
- 1
src/native/mac/juce_mac_MessageManager.mm View File

@@ -82,7 +82,7 @@ public:
JUCEApplication::appWillTerminateByForce(); JUCEApplication::appWillTerminateByForce();
} }
virtual BOOL openFile (const NSString* filename)
virtual BOOL openFile (NSString* filename)
{ {
if (JUCEApplication::getInstance() != 0) if (JUCEApplication::getInstance() != 0)
{ {


+ 9
- 4
src/native/windows/juce_win32_AudioCDReader.cpp View File

@@ -2378,11 +2378,16 @@ bool AudioCDBurner::addAudioTrack (AudioSource* audioSource, int numSamples)
zeromem (buffer, bytesPerBlock); 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); hr = pimpl->redbook->AddAudioTrackBlocks (buffer, bytesPerBlock);


+ 1
- 1
src/native/windows/juce_win32_DynamicLibraryLoader.cpp View File

@@ -43,7 +43,7 @@ DynamicLibraryLoader::~DynamicLibraryLoader()
void* DynamicLibraryLoader::findProcAddress (const String& functionName) 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)
} }


+ 1
- 1
src/native/windows/juce_win32_Threads.cpp View File

@@ -331,7 +331,7 @@ void PlatformUtilities::freeDynamicLibrary (void* h)
void* PlatformUtilities::getProcedureEntryPoint (void* h, const String& name) 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)
} }


+ 37
- 80
src/native/windows/juce_win32_WASAPI.cpp View File

@@ -232,11 +232,12 @@ public:
Array <double> rates; Array <double> rates;
HANDLE clientEvent; HANDLE clientEvent;
BigInteger channels; BigInteger channels;
AudioDataConverters::DataFormat dataFormat;
Array <int> channelMaps; Array <int> channelMaps;
UINT32 actualBufferSize; UINT32 actualBufferSize;
int bytesPerSample; int bytesPerSample;
virtual void updateFormat (bool isFloat) = 0;
private: private:
const ComSmartPtr <IAudioClient> createClient() const ComSmartPtr <IAudioClient> createClient()
{ {
@@ -311,10 +312,8 @@ private:
actualNumChannels = format.Format.nChannels; actualNumChannels = format.Format.nChannels;
const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
bytesPerSample = format.Format.wBitsPerSample / 8; bytesPerSample = format.Format.wBitsPerSample / 8;
dataFormat = isFloat ? AudioDataConverters::float32LE
: (bytesPerSample == 4 ? AudioDataConverters::int32LE
: ((bytesPerSample == 3 ? AudioDataConverters::int24LE
: AudioDataConverters::int16LE)));
updateFormat (isFloat);
return true; return true;
} }
@@ -356,6 +355,20 @@ public:
reservoir.setSize (0); 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) void copyBuffers (float** destBuffers, int numDestBuffers, int bufferSize, Thread& thread)
{ {
if (numChannels <= 0) if (numChannels <= 0)
@@ -370,31 +383,7 @@ public:
const int samplesToDo = jmin (bufferSize, (int) reservoirSize); const int samplesToDo = jmin (bufferSize, (int) reservoirSize);
for (int i = 0; i < numDestBuffers; ++i) 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; bufferSize -= samplesToDo;
offset += samplesToDo; offset += samplesToDo;
@@ -424,31 +413,7 @@ public:
const int samplesToDo = jmin (bufferSize, (int) numSamplesAvailable); const int samplesToDo = jmin (bufferSize, (int) numSamplesAvailable);
for (int i = 0; i < numDestBuffers; ++i) 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; bufferSize -= samplesToDo;
offset += samplesToDo; offset += samplesToDo;
@@ -469,6 +434,7 @@ public:
ComSmartPtr <IAudioCaptureClient> captureClient; ComSmartPtr <IAudioCaptureClient> captureClient;
MemoryBlock reservoir; MemoryBlock reservoir;
int reservoirSize, reservoirCapacity; int reservoirSize, reservoirCapacity;
ScopedPointer <AudioData::Converter> converter;
private: private:
WASAPIInputDevice (const WASAPIInputDevice&); WASAPIInputDevice (const WASAPIInputDevice&);
@@ -501,6 +467,20 @@ public:
renderClient = 0; 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) void copyBuffers (const float** const srcBuffers, const int numSrcBuffers, int bufferSize, Thread& thread)
{ {
if (numChannels <= 0) if (numChannels <= 0)
@@ -530,31 +510,7 @@ public:
if (OK (renderClient->GetBuffer (samplesToDo, &outputData))) if (OK (renderClient->GetBuffer (samplesToDo, &outputData)))
{ {
for (int i = 0; i < numSrcBuffers; ++i) 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); renderClient->ReleaseBuffer (samplesToDo, 0);
@@ -565,6 +521,7 @@ public:
} }
ComSmartPtr <IAudioRenderClient> renderClient; ComSmartPtr <IAudioRenderClient> renderClient;
ScopedPointer <AudioData::Converter> converter;
private: private:
WASAPIOutputDevice (const WASAPIOutputDevice&); WASAPIOutputDevice (const WASAPIOutputDevice&);


+ 2
- 2
src/text/juce_String.cpp View File

@@ -350,7 +350,7 @@ namespace NumberToStringConverters
static juce_wchar getDecimalPoint() 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(); static juce_wchar dp = std::_USE (std::locale(), std::numpunct <wchar_t>).decimal_point();
#else #else
static juce_wchar dp = std::use_facet <std::numpunct <wchar_t> > (std::locale()).decimal_point(); static juce_wchar dp = std::use_facet <std::numpunct <wchar_t> > (std::locale()).decimal_point();
@@ -387,7 +387,7 @@ namespace NumberToStringConverters
else else
{ {
#if JUCE_WINDOWS #if JUCE_WINDOWS
#if _MSC_VER <= 1400
#if JUCE_MSVC && _MSC_VER <= 1400
len = _snwprintf (buffer, numChars, L"%.9g", n); len = _snwprintf (buffer, numChars, L"%.9g", n);
#else #else
len = _snwprintf_s (buffer, numChars, _TRUNCATE, L"%.9g", n); len = _snwprintf_s (buffer, numChars, _TRUNCATE, L"%.9g", n);


Loading…
Cancel
Save