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"
#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


+ 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...
class DemoThumbnailComp : public Component,
public ChangeListener
public ChangeListener,
public FileDragAndDropTarget
{
public:
DemoThumbnailComp()
@@ -104,6 +105,19 @@ public:
repaint();
}
bool isInterestedInFileDrag (const StringArray& files)
{
return true;
}
void filesDropped (const StringArray& files, int x, int y)
{
AudioDemoPlaybackPage* demoPage = findParentComponentOfClass ((AudioDemoPlaybackPage*) 0);
if (demoPage != 0)
demoPage->showFile (File (files[0]));
}
AudioFormatManager formatManager;
AudioThumbnailCache thumbnailCache;
AudioThumbnail thumbnail;
@@ -266,6 +280,14 @@ void AudioDemoPlaybackPage::sliderValueChanged (Slider* sliderThatWasMoved)
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
void AudioDemoPlaybackPage::showFile (const File& file)
{
loadFileIntoTransport (file);
zoomSlider->setValue (0, false, false);
thumbnail->setFile (file);
}
void AudioDemoPlaybackPage::loadFileIntoTransport (const File& audioFile)
{
// unload the previous file source and delete it..
@@ -292,10 +314,7 @@ void AudioDemoPlaybackPage::loadFileIntoTransport (const File& audioFile)
void AudioDemoPlaybackPage::selectionChanged()
{
loadFileIntoTransport (fileTreeComp->getSelectedFile());
zoomSlider->setValue (0, false, false);
thumbnail->setFile (fileTreeComp->getSelectedFile());
showFile (fileTreeComp->getSelectedFile());
}
void AudioDemoPlaybackPage::fileClicked (const File&, const MouseEvent&)


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

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


+ 3
- 3
juce_Config.h View File

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


+ 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 "../../text/juce_LocalisedStrings.h"
//==============================================================================
static const char* const aiffFormatName = "AIFF file";
static const char* const aiffExtensions[] = { ".aiff", ".aif", 0 };
@@ -72,14 +73,14 @@ public:
hasGotVer = true;
const int ver = input->readIntBigEndian();
if (ver != 0 && ver != (int)0xa2805140)
if (ver != 0 && ver != (int) 0xa2805140)
break;
}
else if (type == chunkName ("COMM"))
{
hasGotType = true;
numChannels = (unsigned int)input->readShortBigEndian();
numChannels = (unsigned int) input->readShortBigEndian();
lengthInSamples = input->readIntBigEndian();
bitsPerSample = input->readShortBigEndian();
bytesPerFrame = (numChannels * bitsPerSample) >> 3;
@@ -167,318 +168,42 @@ public:
input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame);
const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
char tempBuffer [tempBufSize];
while (numSamples > 0)
{
int* left = destSamples[0];
if (left != 0)
left += startOffsetInDestBuffer;
int* right = numDestChannels > 1 ? destSamples[1] : 0;
if (right != 0)
right += startOffsetInDestBuffer;
const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
char tempBuffer [tempBufSize];
const int numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples);
const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame);
if (bytesRead < numThisTime * bytesPerFrame)
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;
}
if (numSamples > 0)
{
for (int i = numDestChannels; --i >= 0;)
if (destSamples[i] != 0)
zeromem (destSamples[i] + startOffsetInDestBuffer,
sizeof (int) * numSamples);
}
return true;
}
@@ -509,6 +226,68 @@ private:
//==============================================================================
class AiffAudioFormatWriter : public AudioFormatWriter
{
public:
//==============================================================================
AiffAudioFormatWriter (OutputStream* out, double sampleRate_, unsigned int numChans, int bits)
: AudioFormatWriter (out, TRANS (aiffFormatName), sampleRate_, numChans, bits),
lengthInSamples (0),
bytesWritten (0),
writeFailed (false)
{
headerPosition = out->getPosition();
writeHeader();
}
~AiffAudioFormatWriter()
{
if ((bytesWritten & 1) != 0)
output->writeByte (0);
writeHeader();
}
//==============================================================================
bool write (const int** data, int numSamples)
{
jassert (data != 0 && *data != 0); // the input must contain at least one channel!
if (writeFailed)
return false;
const int bytes = numChannels * numSamples * bitsPerSample / 8;
tempBlock.ensureSize (bytes, false);
switch (bitsPerSample)
{
case 8: WriteHelper<AudioData::Int8, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
case 16: WriteHelper<AudioData::Int16, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
case 24: WriteHelper<AudioData::Int24, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
case 32: WriteHelper<AudioData::Int32, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
default: jassertfalse; break;
}
if (bytesWritten + bytes >= (uint32) 0xfff00000
|| ! output->write (tempBlock.getData(), bytes))
{
// failed to write to disk, so let's try writing the header.
// If it's just run out of disk space, then if it does manage
// to write the header, we'll still have a useable file..
writeHeader();
writeFailed = true;
return false;
}
else
{
bytesWritten += bytes;
lengthInSamples += numSamples;
return true;
}
}
juce_UseDebuggingNewOperator
private:
MemoryBlock tempBlock;
uint32 lengthInSamples, bytesWritten;
int64 headerPosition;
@@ -592,153 +371,6 @@ class AiffAudioFormatWriter : public AudioFormatWriter
jassert (output->getPosition() == headerLen);
}
public:
//==============================================================================
AiffAudioFormatWriter (OutputStream* out,
const double sampleRate_,
const unsigned int chans,
const int bits)
: AudioFormatWriter (out,
TRANS (aiffFormatName),
sampleRate_,
chans,
bits),
lengthInSamples (0),
bytesWritten (0),
writeFailed (false)
{
headerPosition = out->getPosition();
writeHeader();
}
~AiffAudioFormatWriter()
{
if ((bytesWritten & 1) != 0)
output->writeByte (0);
writeHeader();
}
//==============================================================================
bool write (const int** data, int numSamples)
{
if (writeFailed)
return false;
const int bytes = numChannels * numSamples * bitsPerSample / 8;
tempBlock.ensureSize (bytes, false);
char* buffer = static_cast <char*> (tempBlock.getData());
const int* left = data[0];
const int* right = data[1];
if (right == 0)
right = left;
if (bitsPerSample == 16)
{
short* b = reinterpret_cast <short*> (buffer);
if (numChannels > 1)
{
for (int i = numSamples; --i >= 0;)
{
*b++ = (short) ByteOrder::swapIfLittleEndian ((uint16) (*left++ >> 16));
*b++ = (short) ByteOrder::swapIfLittleEndian ((uint16) (*right++ >> 16));
}
}
else
{
for (int i = numSamples; --i >= 0;)
{
*b++ = (short) ByteOrder::swapIfLittleEndian ((uint16) (*left++ >> 16));
}
}
}
else if (bitsPerSample == 24)
{
char* b = buffer;
if (numChannels > 1)
{
for (int i = numSamples; --i >= 0;)
{
ByteOrder::bigEndian24BitToChars (*left++ >> 8, b);
b += 3;
ByteOrder::bigEndian24BitToChars (*right++ >> 8, b);
b += 3;
}
}
else
{
for (int i = numSamples; --i >= 0;)
{
ByteOrder::bigEndian24BitToChars (*left++ >> 8, b);
b += 3;
}
}
}
else if (bitsPerSample == 32)
{
uint32* b = reinterpret_cast <uint32*> (buffer);
if (numChannels > 1)
{
for (int i = numSamples; --i >= 0;)
{
*b++ = ByteOrder::swapIfLittleEndian ((uint32) *left++);
*b++ = ByteOrder::swapIfLittleEndian ((uint32) *right++);
}
}
else
{
for (int i = numSamples; --i >= 0;)
{
*b++ = ByteOrder::swapIfLittleEndian ((uint32) *left++);
}
}
}
else if (bitsPerSample == 8)
{
char* b = buffer;
if (numChannels > 1)
{
for (int i = numSamples; --i >= 0;)
{
*b++ = (char) (*left++ >> 24);
*b++ = (char) (*right++ >> 24);
}
}
else
{
for (int i = numSamples; --i >= 0;)
{
*b++ = (char) (*left++ >> 24);
}
}
}
if (bytesWritten + bytes >= (uint32) 0xfff00000
|| ! output->write (buffer, bytes))
{
// failed to write to disk, so let's try writing the header.
// If it's just run out of disk space, then if it does manage
// to write the header, we'll still have a useable file..
writeHeader();
writeFailed = true;
return false;
}
else
{
bytesWritten += bytes;
lengthInSamples += numSamples;
return true;
}
}
juce_UseDebuggingNewOperator
};
//==============================================================================
@@ -763,15 +395,8 @@ const Array <int> AiffAudioFormat::getPossibleBitDepths()
return Array <int> (depths);
}
bool AiffAudioFormat::canDoStereo()
{
return true;
}
bool AiffAudioFormat::canDoMono()
{
return true;
}
bool AiffAudioFormat::canDoStereo() { return true; }
bool AiffAudioFormat::canDoMono() { return true; }
#if JUCE_MAC
bool AiffAudioFormat::canHandleFile (const File& f)
@@ -785,8 +410,7 @@ bool AiffAudioFormat::canHandleFile (const File& f)
}
#endif
AudioFormatReader* AiffAudioFormat::createReaderFor (InputStream* sourceStream,
const bool deleteStreamIfOpeningFails)
AudioFormatReader* AiffAudioFormat::createReaderFor (InputStream* sourceStream, const bool deleteStreamIfOpeningFails)
{
ScopedPointer <AiffAudioFormatReader> w (new AiffAudioFormatReader (sourceStream));
@@ -801,18 +425,13 @@ AudioFormatReader* AiffAudioFormat::createReaderFor (InputStream* sourceStream,
AudioFormatWriter* AiffAudioFormat::createWriterFor (OutputStream* out,
double sampleRate,
unsigned int chans,
unsigned int numberOfChannels,
int bitsPerSample,
const StringPairArray& /*metadataValues*/,
int /*qualityOptionIndex*/)
{
if (getPossibleBitDepths().contains (bitsPerSample))
{
return new AiffAudioFormatWriter (out,
sampleRate,
chans,
bitsPerSample);
}
return new AiffAudioFormatWriter (out, sampleRate, numberOfChannels, bitsPerSample);
return 0;
}


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

@@ -28,6 +28,7 @@
#include "../../io/streams/juce_InputStream.h"
#include "../../text/juce_StringPairArray.h"
#include "../dsp/juce_AudioDataConverters.h"
class AudioFormat;
@@ -218,6 +219,32 @@ public:
//==============================================================================
juce_UseDebuggingNewOperator
protected:
/** Used by AudioFormatReader subclasses to copy data to different formats. */
template <class DestSampleType, class SourceSampleType, class SourceEndianness>
struct ReadHelper
{
typedef AudioData::Pointer <DestSampleType, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DestType;
typedef AudioData::Pointer <SourceSampleType, SourceEndianness, AudioData::Interleaved, AudioData::Const> SourceType;
static void read (int** destData, int destOffset, int numDestChannels, const void* sourceData, int numSourceChannels, int numSamples) throw()
{
for (int i = 0; i < numDestChannels; ++i)
{
if (destData[i] != 0)
{
DestType dest (destData[i]);
dest += destOffset;
if (i < numSourceChannels)
dest.convertSamples (SourceType (addBytesToPointer (sourceData, i * SourceType::getBytesPerSample()), numSourceChannels), numSamples);
else
dest.clearSamples (numSamples);
}
}
}
};
private:
String formatName;


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

@@ -160,6 +160,26 @@ protected:
/** The output stream for Use by subclasses. */
OutputStream* output;
/** Used by AudioFormatWriter subclasses to copy data to different formats. */
template <class DestSampleType, class SourceSampleType, class DestEndianness>
struct WriteHelper
{
typedef AudioData::Pointer <DestSampleType, DestEndianness, AudioData::Interleaved, AudioData::NonConst> DestType;
typedef AudioData::Pointer <SourceSampleType, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SourceType;
static void write (void* destData, int numDestChannels, const int** source, int numSamples) throw()
{
for (int i = 0; i < numDestChannels; ++i)
{
const DestType dest (addBytesToPointer (destData, i * DestType::getBytesPerSample()), numDestChannels);
dest.convertSamples (SourceType (*source), numSamples);
if (source[1] != 0)
++source;
}
}
};
private:
String formatName;


+ 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 wavExtensions[] = { ".wav", ".bwf", 0 };
//==============================================================================
const char* const WavAudioFormat::bwavDescription = "bwav description";
const char* const WavAudioFormat::bwavOriginator = "bwav originator";
@@ -258,17 +257,7 @@ struct ExtensibleWavSubFormat
//==============================================================================
class WavAudioFormatReader : public AudioFormatReader
{
int bytesPerFrame;
int64 dataChunkStart, dataLength;
static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
WavAudioFormatReader (const WavAudioFormatReader&);
WavAudioFormatReader& operator= (const WavAudioFormatReader&);
public:
int64 bwavChunkStart, bwavSize;
//==============================================================================
WavAudioFormatReader (InputStream* const in)
: AudioFormatReader (in, TRANS (wavFormatName)),
@@ -389,6 +378,7 @@ public:
bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples)
{
jassert (destSamples != 0);
const int64 samplesAvailable = lengthInSamples - startSampleInFile;
if (samplesAvailable < numSamples)
@@ -405,267 +395,55 @@ public:
input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame);
const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
char tempBuffer [tempBufSize];
while (numSamples > 0)
{
int* left = destSamples[0];
if (left != 0)
left += startOffsetInDestBuffer;
int* right = numDestChannels > 1 ? destSamples[1] : 0;
if (right != 0)
right += startOffsetInDestBuffer;
const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
char tempBuffer [tempBufSize];
const int numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples);
const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame);
if (bytesRead < numThisTime * bytesPerFrame)
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;
numSamples -= numThisTime;
}
if (numSamples > 0)
{
for (int i = numDestChannels; --i >= 0;)
if (destSamples[i] != 0)
zeromem (destSamples[i] + startOffsetInDestBuffer,
sizeof (int) * numSamples);
}
return true;
}
int64 bwavChunkStart, bwavSize;
juce_UseDebuggingNewOperator
};
//==============================================================================
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); }
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:
//==============================================================================
WavAudioFormatWriter (OutputStream* const out,
@@ -700,104 +478,25 @@ public:
//==============================================================================
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);
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
|| ! output->write (buffer, bytes))
|| ! 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
@@ -816,6 +515,63 @@ public:
}
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);
}
bool WavAudioFormat::canDoStereo()
{
return true;
}
bool WavAudioFormat::canDoMono()
{
return true;
}
bool WavAudioFormat::canDoStereo() { return true; }
bool WavAudioFormat::canDoMono() { return true; }
AudioFormatReader* WavAudioFormat::createReaderFor (InputStream* sourceStream,
const bool deleteStreamIfOpeningFails)


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

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

@@ -26,7 +26,6 @@
#ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__
#define __JUCE_AUDIODATACONVERTERS_JUCEHEADER__
#if 0
//==============================================================================
/**
@@ -42,6 +41,7 @@ public:
// These types can be used as the SampleFormat template parameter for the AudioData::Pointer class.
class Int8; /**< Used as a template parameter for AudioData::Pointer. Indicates an 8-bit integer packed data format. */
class UInt8; /**< Used as a template parameter for AudioData::Pointer. Indicates an 8-bit unsigned integer packed data format. */
class Int16; /**< Used as a template parameter for AudioData::Pointer. Indicates an 16-bit integer packed data format. */
class Int24; /**< Used as a template parameter for AudioData::Pointer. Indicates an 24-bit integer packed data format. */
class Int32; /**< Used as a template parameter for AudioData::Pointer. Indicates an 32-bit integer packed data format. */
@@ -118,20 +118,19 @@ public:
: InterleavingType (numInterleavedChannels),
data (Constness::toVoidPtr (sourceData))
{
// If you're using non-interleaved data, call the other constructor! If you're using non-interleaved data,
// you should pass NonInterleaved as the template parameter for the interleaving type!
static_jassert (InterleavingType::isInterleavedType != 0);
}
/** Creates a copy of another pointer. */
Pointer (const Pointer& other) throw()
: data (other.data)
: InterleavingType (other),
data (other.data)
{
}
Pointer& operator= (const Pointer& other) throw()
{
data = other.data;
InterleavingType::copyFrom (other);
return *this;
}
@@ -172,9 +171,12 @@ public:
Endianness::setAsInt32 (data, newValue);
}
/** Adds a number of samples to the pointer's position. */
/** Moves the pointer along to the next sample. */
inline Pointer& operator++() throw() { advance(); return *this; }
/** Moves the pointer back to the previous sample. */
inline Pointer& operator--() throw() { advanceDataBy (data, -1); return *this; }
/** Adds a number of samples to the pointer's position. */
Pointer& operator+= (int samplesToJump) throw() { advanceDataBy (data, samplesToJump); return *this; }
@@ -203,12 +205,31 @@ public:
static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead!
Pointer dest (*this);
while (--numSamples >= 0)
if (source.getRawData() != getRawData() || source.getNumBytesBetweenSamples() >= getNumBytesBetweenSamples())
{
Endianness::copyFrom (dest.data, source);
dest.advance();
++source;
while (--numSamples >= 0)
{
Endianness::copyFrom (dest.data, source);
dest.advance();
++source;
}
}
else // copy backwards if we're increasing the sample width..
{
dest += numSamples;
source += numSamples;
while (--numSamples >= 0)
Endianness::copyFrom ((--dest).data, --source);
}
}
/** Sets a number of samples to zero. */
void clearSamples (int numSamples) const throw()
{
Pointer dest (*this);
dest.clear (dest.data, numSamples);
}
/** Returns true if the pointer is using a floating-point format. */
@@ -217,9 +238,15 @@ public:
/** Returns true if the format is big-endian. */
static bool isBigEndian() throw() { return (bool) Endianness::isBigEndian; }
/** Returns the number of bytes in each sample (ignoring the number of interleaved channels). */
static int getBytesPerSample() throw() { return (int) SampleFormat::bytesPerSample; }
/** Returns the number of interleaved channels in the format. */
int getNumInterleavedChannels() const throw() { return (int) this->numInterleavedChannels; }
/** Returns the number of bytes between the start address of each sample. */
int getNumBytesBetweenSamples() const throw() { return InterleavingType::getNumBytesBetweenSamples (data); }
/** Returns the accuracy of this format when represented as a 32-bit integer.
This is the smallest number above 0 that can be represented in the sample format, converted to
a 32-bit range. E,g. if the format is 8-bit, its resolution is 0x01000000; if the format is 24-bit,
@@ -227,6 +254,9 @@ public:
*/
static int get32BitResolution() throw() { return (int) SampleFormat::resolution; }
/** Returns a pointer to the underlying data. */
const void* getRawData() const throw() { return data.data; }
private:
//==============================================================================
SampleFormat data;
@@ -248,9 +278,15 @@ public:
public:
virtual ~Converter() {}
/**
/** Converts a sequence of samples from the converter's source format into the dest format. */
virtual void convertSamples (void* destSamples, const void* sourceSamples, int numSamples) const = 0;
/** Converts a sequence of samples from the converter's source format into the dest format.
This method takes sub-channel indexes, which can be used with interleaved formats in order to choose a
particular sub-channel of the data to be used.
*/
virtual void convertSamples (void* dest, const void* source, int numSamples) const = 0;
virtual void convertSamples (void* destSamples, int destSubChannel,
const void* sourceSamples, int sourceSubChannel, int numSamples) const = 0;
};
//==============================================================================
@@ -266,19 +302,34 @@ public:
class ConverterInstance : public Converter
{
public:
ConverterInstance() {}
ConverterInstance (int numSourceChannels = 1, int numDestChannels = 1)
: sourceChannels (numSourceChannels), destChannels (numDestChannels)
{}
~ConverterInstance() {}
void convertSamples (void* dest, const void* source, int numSamples) const
{
SourceSampleType s (source);
DestSampleType d (dest);
SourceSampleType s (source, sourceChannels);
DestSampleType d (dest, destChannels);
d.convertSamples (s, numSamples);
}
void convertSamples (void* dest, int destSubChannel,
const void* source, int sourceSubChannel, int numSamples) const
{
jassert (destSubChannel < destChannels && sourceSubChannel < sourceChannels);
SourceSampleType s (addBytesToPointer (source, sourceSubChannel * SourceSampleType::getBytesPerSample()), sourceChannels);
DestSampleType d (addBytesToPointer (dest, destSubChannel * DestSampleType::getBytesPerSample()), destChannels);
d.convertSamples (s, numSamples);
}
private:
ConverterInstance (const ConverterInstance&);
ConverterInstance& operator= (const ConverterInstance&);
const int sourceChannels, destChannels;
};
};
@@ -324,18 +375,45 @@ public:
inline void skip (int numSamples) throw() { data += numSamples; }
inline float getAsFloatLE() const throw() { return (float) (*data * (1.0 / (1.0 + maxValue))); }
inline float getAsFloatBE() const throw() { return getAsFloatLE(); }
inline void setAsFloatLE (float newValue) throw() { *data = jlimit ((int8) -maxValue, (int8) maxValue, (int8) roundToInt (newValue * (1.0 + maxValue))); }
inline void setAsFloatLE (float newValue) throw() { *data = (int8) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))); }
inline void setAsFloatBE (float newValue) throw() { setAsFloatLE (newValue); }
inline int32 getAsInt32LE() const throw() { return (int) (*data << 24); }
inline int32 getAsInt32BE() const throw() { return getAsInt32LE(); }
inline void setAsInt32LE (int newValue) throw() { *data = (int8) (newValue >> 24); }
inline void setAsInt32BE (int newValue) throw() { setAsInt32LE (newValue); }
inline void clear() throw() { *data = 0; }
inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;}
template <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); }
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); }
inline void copyFromSameType (Int8& source) throw() { *data = *source.data; }
int8* data;
enum { maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 };
enum { bytesPerSample = 1, maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 };
};
class AudioData::UInt8
{
public:
inline UInt8 (void* data_) throw() : data (static_cast <uint8*> (data_)) {}
inline void advance() throw() { ++data; }
inline void skip (int numSamples) throw() { data += numSamples; }
inline float getAsFloatLE() const throw() { return (float) ((*data - 128) * (1.0 / (1.0 + maxValue))); }
inline float getAsFloatBE() const throw() { return getAsFloatLE(); }
inline void setAsFloatLE (float newValue) throw() { *data = (uint8) jlimit (0, 255, 128 + roundToInt (newValue * (1.0 + maxValue))); }
inline void setAsFloatBE (float newValue) throw() { setAsFloatLE (newValue); }
inline int32 getAsInt32LE() const throw() { return (int) ((*data - 128) << 24); }
inline int32 getAsInt32BE() const throw() { return getAsInt32LE(); }
inline void setAsInt32LE (int newValue) throw() { *data = (uint8) (128 + (newValue >> 24)); }
inline void setAsInt32BE (int newValue) throw() { setAsInt32LE (newValue); }
inline void clear() throw() { *data = 128; }
inline void clearMultiple (int num) throw() { memset (data, 128, num) ;}
template <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); }
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); }
inline void copyFromSameType (UInt8& source) throw() { *data = *source.data; }
uint8* data;
enum { bytesPerSample = 1, maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 };
};
class AudioData::Int16
@@ -353,12 +431,14 @@ public:
inline int32 getAsInt32BE() const throw() { return (int32) (ByteOrder::swapIfLittleEndian ((uint16) *data) << 16); }
inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) (newValue >> 16)); }
inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) (newValue >> 16)); }
inline void clear() throw() { *data = 0; }
inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;}
template <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); }
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); }
inline void copyFromSameType (Int16& source) throw() { *data = *source.data; }
uint16* data;
enum { maxValue = 0x7fff, resolution = (1 << 16), isFloat = 0 };
enum { bytesPerSample = 2, maxValue = 0x7fff, resolution = (1 << 16), isFloat = 0 };
};
class AudioData::Int24
@@ -376,12 +456,14 @@ public:
inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::bigEndian24Bit (data) << 8; }
inline void setAsInt32LE (int32 newValue) throw() { ByteOrder::littleEndian24BitToChars (newValue >> 8, data); }
inline void setAsInt32BE (int32 newValue) throw() { ByteOrder::bigEndian24BitToChars (newValue >> 8, data); }
inline void clear() throw() { data[0] = 0; data[1] = 0; data[2] = 0; }
inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;}
template <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); }
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); }
inline void copyFromSameType (Int24& source) throw() { data[0] = source.data[0]; data[1] = source.data[1]; data[2] = source.data[2]; }
char* data;
enum { maxValue = 0x7fffff, resolution = (1 << 8), isFloat = 0 };
enum { bytesPerSample = 3, maxValue = 0x7fffff, resolution = (1 << 8), isFloat = 0 };
};
class AudioData::Int32
@@ -399,12 +481,14 @@ public:
inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::swapIfLittleEndian (*data); }
inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); }
inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) newValue); }
inline void clear() throw() { *data = 0; }
inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;}
template <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); }
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); }
inline void copyFromSameType (Int32& source) throw() { *data = *source.data; }
uint32* data;
enum { maxValue = 0x7fffffff, resolution = 1, isFloat = 0 };
enum { bytesPerSample = 4, maxValue = 0x7fffffff, resolution = 1, isFloat = 0 };
};
class AudioData::Float32
@@ -429,12 +513,14 @@ public:
inline int32 getAsInt32BE() const throw() { return (int32) roundToInt (jlimit (-1.0f, 1.0f, getAsFloatBE()) * (1.0 + maxValue)); }
inline void setAsInt32LE (int32 newValue) throw() { setAsFloatLE ((float) (newValue * (1.0 / (1.0 + maxValue)))); }
inline void setAsInt32BE (int32 newValue) throw() { setAsFloatBE ((float) (newValue * (1.0 / (1.0 + maxValue)))); }
inline void clear() throw() { *data = 0; }
inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;}
template <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); }
template <class SourceType> inline void copyFromBE (SourceType& source) throw() { setAsFloatBE (source.getAsFloat()); }
inline void copyFromSameType (Float32& source) throw() { *data = *source.data; }
float* data;
enum { maxValue = 0x7fffffff, resolution = (1 << 8), isFloat = 1 };
enum { bytesPerSample = 4, maxValue = 0x7fffffff, resolution = (1 << 8), isFloat = 1 };
};
//==============================================================================
@@ -442,9 +528,14 @@ class AudioData::NonInterleaved
{
public:
inline NonInterleaved() throw() {}
inline NonInterleaved (const NonInterleaved&) throw() {}
inline NonInterleaved (const int) throw() {}
template <class SampleFormatType> inline void advanceData (SampleFormatType& s) throw() { s.advance(); }
template <class SampleFormatType> inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numSamples); }
inline void copyFrom (const NonInterleaved&) throw() {}
template <class SampleFormatType> inline void advanceData (SampleFormatType& s) throw() { s.advance(); }
template <class SampleFormatType> inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numSamples); }
template <class SampleFormatType> inline void clear (SampleFormatType& s, int numSamples) throw() { s.clearMultiple (numSamples); }
template <class SampleFormatType> inline static int getNumBytesBetweenSamples (const SampleFormatType&) throw() { return SampleFormatType::bytesPerSample; }
enum { isInterleavedType = 0, numInterleavedChannels = 1 };
};
@@ -452,14 +543,15 @@ class AudioData::Interleaved
{
public:
inline Interleaved() throw() : numInterleavedChannels (1) {}
inline Interleaved (const Interleaved& other) throw() : numInterleavedChannels (other.numInterleavedChannels) {}
inline Interleaved (const int numInterleavedChannels_) throw() : numInterleavedChannels (numInterleavedChannels_) {}
inline void copyFrom (const Interleaved& other) throw() { numInterleavedChannels = other.numInterleavedChannels; }
template <class SampleFormatType> inline void advanceData (SampleFormatType& s) throw() { s.skip (numInterleavedChannels); }
template <class SampleFormatType> inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numInterleavedChannels * numSamples); }
const int numInterleavedChannels;
template <class SampleFormatType> inline void clear (SampleFormatType& s, int numSamples) throw() { while (--numSamples >= 0) { s.clear(); s.skip (numInterleavedChannels); } }
template <class SampleFormatType> inline int getNumBytesBetweenSamples (const SampleFormatType& s) const throw() { return numInterleavedChannels * s.bytesPerSample; }
int numInterleavedChannels;
enum { isInterleavedType = 1 };
private:
Interleaved& operator= (const Interleaved&);
};
//==============================================================================
@@ -481,8 +573,6 @@ public:
#endif
#endif
//==============================================================================
/**
A set of routines to convert buffers of 32-bit floating point data to and from


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

@@ -528,13 +528,17 @@ public:
/** Removes a previously added listener. */
void removeListener (AudioProcessorListener* listenerToRemove);
//==============================================================================
/** Tells the processor to use this playhead object.
The processor will not take ownership of the object, so the caller must delete it when
it is no longer being used.
*/
void setPlayHead (AudioPlayHead* newPlayHead) throw();
//==============================================================================
/** Not for public use - this is called before deleting an editor component. */
void editorBeingDeleted (AudioProcessorEditor* editor) throw();
/** Not for public use - this is called to initialise the processor. */
void setPlayHead (AudioPlayHead* newPlayHead) throw();
/** Not for public use - this is called to initialise the processor before playing. */
void setPlayConfigDetails (int numIns, int numOuts,
double sampleRate,


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

@@ -122,6 +122,12 @@ public:
*/
inline operator void*() const throw() { return static_cast <void*> (data); }
/** Returns a void pointer to the allocated data.
This may be a null pointer if the data hasn't yet been allocated, or if it has been
freed by calling the free() method.
*/
inline operator const void*() const throw() { return static_cast <const void*> (data); }
/** Lets you use indirect calls to the first element in the array.
Obviously this will cause problems if the array hasn't been initialised, because it'll
be referencing a null pointer.


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

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


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

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


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

@@ -525,7 +525,7 @@ public:
@see Component::createComponentSnapshot
*/
const Image createSnapshotOfSelectedRows (int& x, int& y);
virtual const Image createSnapshotOfSelectedRows (int& x, int& y);
/** Returns the viewport that this ListBox uses.


+ 82
- 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)
{
snd_pcm_t* pcmHandle;
if (snd_pcm_open (&pcmHandle, deviceID.toUTF8(), SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC | SND_PCM_NONBLOCK ) >= 0)
if (snd_pcm_open (&pcmHandle, deviceID.toUTF8(), SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC | SND_PCM_NONBLOCK) >= 0)
{
getDeviceNumChannels (pcmHandle, &minChansOut, &maxChansOut);
getDeviceSampleRates (pcmHandle, rates);
@@ -96,7 +96,7 @@ static void getDeviceProperties (const String& deviceID,
if (snd_ctl_pcm_info (handle, info) >= 0)
{
snd_pcm_t* pcmHandle;
if (snd_pcm_open (&pcmHandle, deviceID.toUTF8(), SND_PCM_STREAM_CAPTURE, SND_PCM_ASYNC | SND_PCM_NONBLOCK ) >= 0)
if (snd_pcm_open (&pcmHandle, deviceID.toUTF8(), SND_PCM_STREAM_CAPTURE, SND_PCM_ASYNC | SND_PCM_NONBLOCK) >= 0)
{
getDeviceNumChannels (pcmHandle, &minChansIn, &maxChansIn);
@@ -115,14 +115,12 @@ static void getDeviceProperties (const String& deviceID,
class ALSADevice
{
public:
ALSADevice (const String& deviceID,
const bool forInput)
ALSADevice (const String& deviceID, bool forInput)
: handle (0),
bitDepth (16),
numChannelsRunning (0),
latency (0),
isInput (forInput),
sampleFormat (AudioDataConverters::int16LE)
isInput (forInput)
{
failed (snd_pcm_open (&handle, deviceID.toUTF8(),
forInput ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
@@ -156,22 +154,26 @@ public:
return false;
}
const int formatsToTry[] = { SND_PCM_FORMAT_FLOAT_LE, 32, AudioDataConverters::float32LE,
SND_PCM_FORMAT_FLOAT_BE, 32, AudioDataConverters::float32BE,
SND_PCM_FORMAT_S32_LE, 32, AudioDataConverters::int32LE,
SND_PCM_FORMAT_S32_BE, 32, AudioDataConverters::int32BE,
SND_PCM_FORMAT_S24_3LE, 24, AudioDataConverters::int24LE,
SND_PCM_FORMAT_S24_3BE, 24, AudioDataConverters::int24BE,
SND_PCM_FORMAT_S16_LE, 16, AudioDataConverters::int16LE,
SND_PCM_FORMAT_S16_BE, 16, AudioDataConverters::int16BE };
enum { isFloatBit = 1 << 16, isLittleEndianBit = 1 << 17 };
const int formatsToTry[] = { SND_PCM_FORMAT_FLOAT_LE, 32 | isFloatBit | isLittleEndianBit,
SND_PCM_FORMAT_FLOAT_BE, 32 | isFloatBit,
SND_PCM_FORMAT_S32_LE, 32 | isLittleEndianBit,
SND_PCM_FORMAT_S32_BE, 32,
SND_PCM_FORMAT_S24_3LE, 24 | isLittleEndianBit,
SND_PCM_FORMAT_S24_3BE, 24,
SND_PCM_FORMAT_S16_LE, 16 | isLittleEndianBit,
SND_PCM_FORMAT_S16_BE, 16 };
bitDepth = 0;
for (int i = 0; i < numElementsInArray (formatsToTry); i += 3)
for (int i = 0; i < numElementsInArray (formatsToTry); i += 2)
{
if (snd_pcm_hw_params_set_format (handle, hwParams, (_snd_pcm_format) formatsToTry [i]) >= 0)
{
bitDepth = formatsToTry [i + 1];
sampleFormat = (AudioDataConverters::DataFormat) formatsToTry [i + 2];
bitDepth = formatsToTry [i + 1] & 255;
const bool isFloat = (formatsToTry [i + 1] & isFloatBit) != 0;
const bool isLittleEndian = (formatsToTry [i + 1] & isLittleEndianBit) != 0;
converter = createConverter (isInput, bitDepth, isFloat, isLittleEndian, numChannels);
break;
}
}
@@ -235,48 +237,44 @@ public:
}
//==============================================================================
bool write (AudioSampleBuffer& outputChannelBuffer, const int numSamples)
bool writeToOutputDevice (AudioSampleBuffer& outputChannelBuffer, const int numSamples)
{
jassert (numChannelsRunning <= outputChannelBuffer.getNumChannels());
float** const data = outputChannelBuffer.getArrayOfChannels();
snd_pcm_sframes_t numDone = 0;
if (isInterleaved)
{
scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
float* interleaved = static_cast <float*> (scratch.getData());
AudioDataConverters::interleaveSamples ((const float**) data, interleaved, numSamples, numChannelsRunning);
AudioDataConverters::convertFloatToFormat (sampleFormat, interleaved, interleaved, numSamples * numChannelsRunning);
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
{
for (int i = 0; i < numChannelsRunning; ++i)
if (data[i] != 0)
AudioDataConverters::convertFloatToFormat (sampleFormat, data[i], data[i], numSamples);
converter->convertSamples (data[i], data[i], numSamples);
snd_pcm_sframes_t num = snd_pcm_writen (handle, (void**) data, numSamples);
numDone = snd_pcm_writen (handle, (void**) data, numSamples);
}
if (failed (num))
if (failed (numDone))
{
if (numDone == -EPIPE)
{
if (num == -EPIPE)
{
if (failed (snd_pcm_prepare (handle)))
return false;
}
else if (num != -ESTRPIPE)
if (failed (snd_pcm_prepare (handle)))
return false;
}
else if (numDone != -ESTRPIPE)
return false;
}
return true;
}
bool read (AudioSampleBuffer& inputChannelBuffer, const int numSamples)
bool readFromInputDevice (AudioSampleBuffer& inputChannelBuffer, const int numSamples)
{
jassert (numChannelsRunning <= inputChannelBuffer.getNumChannels());
float** const data = inputChannelBuffer.getArrayOfChannels();
@@ -284,9 +282,8 @@ public:
if (isInterleaved)
{
scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
float* interleaved = static_cast <float*> (scratch.getData());
snd_pcm_sframes_t num = snd_pcm_readi (handle, interleaved, numSamples);
snd_pcm_sframes_t num = snd_pcm_readi (handle, scratch.getData(), numSamples);
if (failed (num))
{
@@ -299,8 +296,8 @@ public:
return false;
}
AudioDataConverters::convertFormatToFloat (sampleFormat, interleaved, interleaved, numSamples * numChannelsRunning);
AudioDataConverters::deinterleaveSamples (interleaved, data, numSamples, numChannelsRunning);
for (int i = 0; i < numChannelsRunning; ++i)
converter->convertSamples (data[i], 0, scratch.getData(), i, numSamples);
}
else
{
@@ -310,8 +307,7 @@ public:
return false;
for (int i = 0; i < numChannelsRunning; ++i)
if (data[i] != 0)
AudioDataConverters::convertFormatToFloat (sampleFormat, data[i], data[i], numSamples);
converter->convertSamples (data[i], data[i], numSamples);
}
return true;
@@ -329,7 +325,48 @@ private:
const bool isInput;
bool isInterleaved;
MemoryBlock scratch;
AudioDataConverters::DataFormat sampleFormat;
ScopedPointer<AudioData::Converter> converter;
//==============================================================================
template <class SampleType>
struct ConverterHelper
{
static AudioData::Converter* createConverter (const bool forInput, const bool isLittleEndian, const int numInterleavedChannels)
{
if (forInput)
{
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DestType;
if (isLittleEndian)
return new AudioData::ConverterInstance <AudioData::Pointer <SampleType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, DestType> (numInterleavedChannels, 1);
else
return new AudioData::ConverterInstance <AudioData::Pointer <SampleType, AudioData::BigEndian, AudioData::Interleaved, AudioData::Const>, DestType> (numInterleavedChannels, 1);
}
else
{
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SourceType;
if (isLittleEndian)
return new AudioData::ConverterInstance <SourceType, AudioData::Pointer <SampleType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, numInterleavedChannels);
else
return new AudioData::ConverterInstance <SourceType, AudioData::Pointer <SampleType, AudioData::BigEndian, AudioData::Interleaved, AudioData::NonConst> > (1, numInterleavedChannels);
}
}
};
static AudioData::Converter* createConverter (const bool forInput, const int bitDepth, const bool isFloat, const bool isLittleEndian, const int numInterleavedChannels)
{
switch (bitDepth)
{
case 16: return ConverterHelper <AudioData::Int16>::createConverter (forInput, isLittleEndian, numInterleavedChannels);
case 24: return ConverterHelper <AudioData::Int24>::createConverter (forInput, isLittleEndian, numInterleavedChannels);
case 32: return isFloat ? ConverterHelper <AudioData::Float32>::createConverter (forInput, isLittleEndian, numInterleavedChannels)
: ConverterHelper <AudioData::Int32>::createConverter (forInput, isLittleEndian, numInterleavedChannels);
default: jassertfalse; break; // unsupported format!
}
return 0;
}
//==============================================================================
bool failed (const int errorNum)
@@ -522,7 +559,7 @@ public:
{
if (inputDevice != 0)
{
if (! inputDevice->read (inputChannelBuffer, bufferSize))
if (! inputDevice->readFromInputDevice (inputChannelBuffer, bufferSize))
{
DBG ("ALSA: read failure");
break;
@@ -560,7 +597,7 @@ public:
failed (snd_pcm_avail_update (outputDevice->handle));
if (! outputDevice->write (outputChannelBuffer, bufferSize))
if (! outputDevice->writeToOutputDevice (outputChannelBuffer, bufferSize))
{
DBG ("ALSA: write failure");
break;


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

@@ -279,10 +279,19 @@ END_JUCE_NAMESPACE
source->getNextAudioBlock (info);
JUCE_NAMESPACE::AudioDataConverters::convertFloatToInt16LE (tempBuffer.getSampleData (0),
buffer, numSamples, 4);
JUCE_NAMESPACE::AudioDataConverters::convertFloatToInt16LE (tempBuffer.getSampleData (1),
buffer + 2, numSamples, 4);
typedef JUCE_NAMESPACE::AudioData::Pointer <JUCE_NAMESPACE::AudioData::Int16,
JUCE_NAMESPACE::AudioData::LittleEndian,
JUCE_NAMESPACE::AudioData::Interleaved,
JUCE_NAMESPACE::AudioData::NonConst> CDSampleFormat;
typedef JUCE_NAMESPACE::AudioData::Pointer <JUCE_NAMESPACE::AudioData::Float32,
JUCE_NAMESPACE::AudioData::NativeEndian,
JUCE_NAMESPACE::AudioData::NonInterleaved,
JUCE_NAMESPACE::AudioData::Const> SourceSampleFormat;
CDSampleFormat left (buffer, 2);
left.convertSamples (SourceSampleFormat (tempBuffer.getSampleData (0)), numSamples);
CDSampleFormat right (buffer + 2, 2);
right.convertSamples (SourceSampleFormat (tempBuffer.getSampleData (1)), numSamples);
readPosition += numSamples;
}


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

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


+ 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!
return jmax (-1, c - 29);
return jmax (-1, (int) c - 29);
}
private:


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

@@ -82,7 +82,7 @@ public:
JUCEApplication::appWillTerminateByForce();
}
virtual BOOL openFile (const NSString* filename)
virtual BOOL openFile (NSString* filename)
{
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);
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);


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

@@ -43,7 +43,7 @@ DynamicLibraryLoader::~DynamicLibraryLoader()
void* DynamicLibraryLoader::findProcAddress (const String& functionName)
{
return GetProcAddress ((HMODULE) libHandle, functionName.toCString());
return (void*) GetProcAddress ((HMODULE) libHandle, functionName.toCString()); // (void* cast is required for mingw)
}


+ 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)
{
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;
HANDLE clientEvent;
BigInteger channels;
AudioDataConverters::DataFormat dataFormat;
Array <int> channelMaps;
UINT32 actualBufferSize;
int bytesPerSample;
virtual void updateFormat (bool isFloat) = 0;
private:
const ComSmartPtr <IAudioClient> createClient()
{
@@ -311,10 +312,8 @@ private:
actualNumChannels = format.Format.nChannels;
const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
bytesPerSample = format.Format.wBitsPerSample / 8;
dataFormat = isFloat ? AudioDataConverters::float32LE
: (bytesPerSample == 4 ? AudioDataConverters::int32LE
: ((bytesPerSample == 3 ? AudioDataConverters::int24LE
: AudioDataConverters::int16LE)));
updateFormat (isFloat);
return true;
}
@@ -356,6 +355,20 @@ public:
reservoir.setSize (0);
}
void updateFormat (bool isFloat)
{
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> NativeType;
if (isFloat)
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Float32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
else if (bytesPerSample == 4)
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Int32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
else if (bytesPerSample == 3)
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Int24, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
else
converter = new AudioData::ConverterInstance <AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1);
}
void copyBuffers (float** destBuffers, int numDestBuffers, int bufferSize, Thread& thread)
{
if (numChannels <= 0)
@@ -370,31 +383,7 @@ public:
const int samplesToDo = jmin (bufferSize, (int) reservoirSize);
for (int i = 0; i < numDestBuffers; ++i)
{
float* const dest = destBuffers[i] + offset;
const int srcChan = channelMaps.getUnchecked(i);
switch (dataFormat)
{
case AudioDataConverters::float32LE:
AudioDataConverters::convertFloat32LEToFloat (((uint8*) reservoir.getData()) + 4 * srcChan, dest, samplesToDo, 4 * actualNumChannels);
break;
case AudioDataConverters::int32LE:
AudioDataConverters::convertInt32LEToFloat (((uint8*) reservoir.getData()) + 4 * srcChan, dest, samplesToDo, 4 * actualNumChannels);
break;
case AudioDataConverters::int24LE:
AudioDataConverters::convertInt24LEToFloat (((uint8*) reservoir.getData()) + 3 * srcChan, dest, samplesToDo, 3 * actualNumChannels);
break;
case AudioDataConverters::int16LE:
AudioDataConverters::convertInt16LEToFloat (((uint8*) reservoir.getData()) + 2 * srcChan, dest, samplesToDo, 2 * actualNumChannels);
break;
default: jassertfalse; break;
}
}
converter->convertSamples (destBuffers[i], offset, reservoir.getData(), channelMaps.getUnchecked(i), samplesToDo);
bufferSize -= samplesToDo;
offset += samplesToDo;
@@ -424,31 +413,7 @@ public:
const int samplesToDo = jmin (bufferSize, (int) numSamplesAvailable);
for (int i = 0; i < numDestBuffers; ++i)
{
float* const dest = destBuffers[i] + offset;
const int srcChan = channelMaps.getUnchecked(i);
switch (dataFormat)
{
case AudioDataConverters::float32LE:
AudioDataConverters::convertFloat32LEToFloat (inputData + 4 * srcChan, dest, samplesToDo, 4 * actualNumChannels);
break;
case AudioDataConverters::int32LE:
AudioDataConverters::convertInt32LEToFloat (inputData + 4 * srcChan, dest, samplesToDo, 4 * actualNumChannels);
break;
case AudioDataConverters::int24LE:
AudioDataConverters::convertInt24LEToFloat (inputData + 3 * srcChan, dest, samplesToDo, 3 * actualNumChannels);
break;
case AudioDataConverters::int16LE:
AudioDataConverters::convertInt16LEToFloat (inputData + 2 * srcChan, dest, samplesToDo, 2 * actualNumChannels);
break;
default: jassertfalse; break;
}
}
converter->convertSamples (destBuffers[i], offset, inputData, channelMaps.getUnchecked(i), samplesToDo);
bufferSize -= samplesToDo;
offset += samplesToDo;
@@ -469,6 +434,7 @@ public:
ComSmartPtr <IAudioCaptureClient> captureClient;
MemoryBlock reservoir;
int reservoirSize, reservoirCapacity;
ScopedPointer <AudioData::Converter> converter;
private:
WASAPIInputDevice (const WASAPIInputDevice&);
@@ -501,6 +467,20 @@ public:
renderClient = 0;
}
void updateFormat (bool isFloat)
{
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> NativeType;
if (isFloat)
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Float32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
else if (bytesPerSample == 4)
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Int32, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
else if (bytesPerSample == 3)
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Int24, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
else
converter = new AudioData::ConverterInstance <NativeType, AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels);
}
void copyBuffers (const float** const srcBuffers, const int numSrcBuffers, int bufferSize, Thread& thread)
{
if (numChannels <= 0)
@@ -530,31 +510,7 @@ public:
if (OK (renderClient->GetBuffer (samplesToDo, &outputData)))
{
for (int i = 0; i < numSrcBuffers; ++i)
{
const float* const source = srcBuffers[i] + offset;
const int destChan = channelMaps.getUnchecked(i);
switch (dataFormat)
{
case AudioDataConverters::float32LE:
AudioDataConverters::convertFloatToFloat32LE (source, outputData + 4 * destChan, samplesToDo, 4 * actualNumChannels);
break;
case AudioDataConverters::int32LE:
AudioDataConverters::convertFloatToInt32LE (source, outputData + 4 * destChan, samplesToDo, 4 * actualNumChannels);
break;
case AudioDataConverters::int24LE:
AudioDataConverters::convertFloatToInt24LE (source, outputData + 3 * destChan, samplesToDo, 3 * actualNumChannels);
break;
case AudioDataConverters::int16LE:
AudioDataConverters::convertFloatToInt16LE (source, outputData + 2 * destChan, samplesToDo, 2 * actualNumChannels);
break;
default: jassertfalse; break;
}
}
converter->convertSamples (outputData, channelMaps.getUnchecked(i), srcBuffers[i], offset, samplesToDo);
renderClient->ReleaseBuffer (samplesToDo, 0);
@@ -565,6 +521,7 @@ public:
}
ComSmartPtr <IAudioRenderClient> renderClient;
ScopedPointer <AudioData::Converter> converter;
private:
WASAPIOutputDevice (const WASAPIOutputDevice&);


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

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


Loading…
Cancel
Save