diff --git a/extras/audio plugins/wrapper/juce_IncludeCharacteristics.h b/extras/audio plugins/wrapper/juce_IncludeCharacteristics.h index 71ebff76dc..37a720c9a5 100644 --- a/extras/audio plugins/wrapper/juce_IncludeCharacteristics.h +++ b/extras/audio plugins/wrapper/juce_IncludeCharacteristics.h @@ -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 diff --git a/extras/juce demo/Source/demos/AudioDemoPlaybackPage.cpp b/extras/juce demo/Source/demos/AudioDemoPlaybackPage.cpp index 30acefc252..158d2ac859 100644 --- a/extras/juce demo/Source/demos/AudioDemoPlaybackPage.cpp +++ b/extras/juce demo/Source/demos/AudioDemoPlaybackPage.cpp @@ -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&) diff --git a/extras/juce demo/Source/demos/AudioDemoPlaybackPage.h b/extras/juce demo/Source/demos/AudioDemoPlaybackPage.h index f622c88090..35238d6ed1 100644 --- a/extras/juce demo/Source/demos/AudioDemoPlaybackPage.h +++ b/extras/juce demo/Source/demos/AudioDemoPlaybackPage.h @@ -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); diff --git a/juce_Config.h b/juce_Config.h index 056e844fae..78a44d5df2 100644 --- a/juce_Config.h +++ b/juce_Config.h @@ -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 diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 22599b5761..966faa9b45 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -298,7 +298,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). @@ -306,7 +306,7 @@ reduce code size. */ #ifndef JUCE_USE_CDREADER - #define JUCE_USE_CDREADER 0 + #define JUCE_USE_CDREADER 1 #endif /** JUCE_USE_CAMERA: Enables web-cam support using the CameraDevice class (Mac and Windows). @@ -388,7 +388,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 @@ -3992,6 +3992,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; } @@ -4002,6 +4003,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; }; @@ -4027,6 +4029,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; }; @@ -4052,6 +4055,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; }; @@ -4076,6 +4080,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; } @@ -4109,6 +4114,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(); } @@ -4135,6 +4141,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"; } @@ -11882,7 +11889,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 ).decimal_point(); #else static juce_wchar dp = std::use_facet > (std::locale()).decimal_point(); @@ -11919,7 +11926,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); @@ -20634,14 +20641,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; @@ -20728,318 +20735,42 @@ public: input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame); - const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3) - char tempBuffer [tempBufSize]; - while (numSamples > 0) { - int* left = destSamples[0]; - if (left != 0) - left += startOffsetInDestBuffer; - - int* right = numDestChannels > 1 ? destSamples[1] : 0; - if (right != 0) - right += startOffsetInDestBuffer; + const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3) + char tempBuffer [tempBufSize]; const int numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples); const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame); if (bytesRead < numThisTime * bytesPerFrame) + { + jassert (bytesRead >= 0); zeromem (tempBuffer + bytesRead, numThisTime * bytesPerFrame - bytesRead); + } - if (bitsPerSample == 16) + jassert (! usesFloatingPointData); // (would need to add support for this if it's possible) + + if (littleEndian) { - if (littleEndian) + switch (bitsPerSample) { - const short* src = reinterpret_cast (tempBuffer); - - if (numChannels > 1) - { - if (left == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *right++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - ++src; - } - } - else if (right == 0) - { - for (int i = numThisTime; --i >= 0;) - { - ++src; - *left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - *right++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - } - } - } - else - { - const char* src = tempBuffer; - - if (numChannels > 1) - { - if (left == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *right++ = ByteOrder::bigEndianShort (src) << 16; - src += 4; - } - } - else if (right == 0) - { - for (int i = numThisTime; --i >= 0;) - { - src += 2; - *left++ = ByteOrder::bigEndianShort (src) << 16; - src += 2; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ByteOrder::bigEndianShort (src) << 16; - src += 2; - *right++ = ByteOrder::bigEndianShort (src) << 16; - src += 2; - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ByteOrder::bigEndianShort (src) << 16; - src += 2; - } - } + case 8: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 16: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 24: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 32: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + default: jassertfalse; break; } } - else if (bitsPerSample == 24) + else { - const char* src = tempBuffer; - - if (littleEndian) + switch (bitsPerSample) { - if (numChannels > 1) - { - if (left == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *right++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 6; - } - } - else if (right == 0) - { - for (int i = numThisTime; --i >= 0;) - { - src += 3; - *left++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - *right++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - } - } - } - else - { - if (numChannels > 1) - { - if (left == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *right++ = ByteOrder::bigEndian24Bit (src) << 8; - src += 6; - } - } - else if (right == 0) - { - for (int i = numThisTime; --i >= 0;) - { - src += 3; - *left++ = ByteOrder::bigEndian24Bit (src) << 8; - src += 3; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ByteOrder::bigEndian24Bit (src) << 8; - src += 3; - *right++ = ByteOrder::bigEndian24Bit (src) << 8; - src += 3; - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ByteOrder::bigEndian24Bit (src) << 8; - src += 3; - } - } - } - } - else if (bitsPerSample == 32) - { - const unsigned int* src = reinterpret_cast (tempBuffer); - unsigned int* l = reinterpret_cast (left); - unsigned int* r = reinterpret_cast (right); - - if (littleEndian) - { - if (numChannels > 1) - { - if (l == 0) - { - for (int i = numThisTime; --i >= 0;) - { - ++src; - *r++ = ByteOrder::swapIfBigEndian (*src++); - } - } - else if (r == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *l++ = ByteOrder::swapIfBigEndian (*src++); - ++src; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *l++ = ByteOrder::swapIfBigEndian (*src++); - *r++ = ByteOrder::swapIfBigEndian (*src++); - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *l++ = ByteOrder::swapIfBigEndian (*src++); - } - } - } - else - { - if (numChannels > 1) - { - if (l == 0) - { - for (int i = numThisTime; --i >= 0;) - { - ++src; - *r++ = ByteOrder::swapIfLittleEndian (*src++); - } - } - else if (r == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *l++ = ByteOrder::swapIfLittleEndian (*src++); - ++src; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *l++ = ByteOrder::swapIfLittleEndian (*src++); - *r++ = ByteOrder::swapIfLittleEndian (*src++); - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *l++ = ByteOrder::swapIfLittleEndian (*src++); - } - } - } - - left = reinterpret_cast (l); - right = reinterpret_cast (r); - } - else if (bitsPerSample == 8) - { - const char* src = tempBuffer; - - if (numChannels > 1) - { - if (left == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *right++ = ((int) *src++) << 24; - ++src; - } - } - else if (right == 0) - { - for (int i = numThisTime; --i >= 0;) - { - ++src; - *left++ = ((int) *src++) << 24; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ((int) *src++) << 24; - *right++ = ((int) *src++) << 24; - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ((int) *src++) << 24; - } + case 8: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 16: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 24: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 32: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + default: jassertfalse; break; } } @@ -21047,14 +20778,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; } @@ -21069,6 +20792,67 @@ 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::write (tempBlock.getData(), numChannels, data, numSamples); break; + case 16: WriteHelper::write (tempBlock.getData(), numChannels, data, numSamples); break; + case 24: WriteHelper::write (tempBlock.getData(), numChannels, data, numSamples); break; + case 32: WriteHelper::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; @@ -21152,152 +20936,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 (tempBlock.getData()); - - const int* left = data[0]; - const int* right = data[1]; - if (right == 0) - right = left; - - if (bitsPerSample == 16) - { - short* b = reinterpret_cast (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 (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 }; AiffAudioFormat::AiffAudioFormat() @@ -21321,15 +20959,8 @@ const Array AiffAudioFormat::getPossibleBitDepths() return Array (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) @@ -21343,8 +20974,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 w (new AiffAudioFormatReader (sourceStream)); @@ -21359,18 +20989,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; } @@ -23310,16 +22935,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)), @@ -23439,6 +23055,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) @@ -23455,211 +23072,127 @@ public: input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame); - const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3) - char tempBuffer [tempBufSize]; - while (numSamples > 0) { - int* left = destSamples[0]; - if (left != 0) - left += startOffsetInDestBuffer; - - int* right = numDestChannels > 1 ? destSamples[1] : 0; - if (right != 0) - right += startOffsetInDestBuffer; + const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3) + char tempBuffer [tempBufSize]; const int numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples); const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame); if (bytesRead < numThisTime * bytesPerFrame) + { + jassert (bytesRead >= 0); zeromem (tempBuffer + bytesRead, numThisTime * bytesPerFrame - bytesRead); - - if (bitsPerSample == 16) - { - const short* src = reinterpret_cast (tempBuffer); - - if (numChannels > 1) - { - if (left == 0) - { - for (int i = numThisTime; --i >= 0;) - { - ++src; - *right++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - } - } - else if (right == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - ++src; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - *right++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - } - } } - else if (bitsPerSample == 24) + + switch (bitsPerSample) { - const char* src = tempBuffer; - - if (numChannels > 1) - { - if (left == 0) - { - for (int i = numThisTime; --i >= 0;) - { - src += 3; - *right++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - } - } - else if (right == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 6; - } - } - else - { - for (int i = 0; i < numThisTime; ++i) - { - *left++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - *right++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - } - } - } - else - { - for (int i = 0; i < numThisTime; ++i) - { - *left++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - } - } - } - else if (bitsPerSample == 32) - { - const unsigned int* src = (const unsigned int*) tempBuffer; - unsigned int* l = reinterpret_cast (left); - unsigned int* r = reinterpret_cast (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 (l); - right = reinterpret_cast (r); - } - else if (bitsPerSample == 8) - { - const unsigned char* src = reinterpret_cast (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::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 16: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 24: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 32: if (usesFloatingPointData) ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); + else ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + default: jassertfalse; break; } startOffsetInDestBuffer += numThisTime; numSamples -= numThisTime; } - if (numSamples > 0) - { - for (int i = numDestChannels; --i >= 0;) - if (destSamples[i] != 0) - zeromem (destSamples[i] + startOffsetInDestBuffer, - sizeof (int) * numSamples); - } - return true; } + int64 bwavChunkStart, bwavSize; + juce_UseDebuggingNewOperator + +private: + ScopedPointer converter; + int bytesPerFrame; + int64 dataChunkStart, dataLength; + + static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); } + + WavAudioFormatReader (const WavAudioFormatReader&); + WavAudioFormatReader& operator= (const WavAudioFormatReader&); }; class WavAudioFormatWriter : public AudioFormatWriter { +public: + + WavAudioFormatWriter (OutputStream* const out, + const double sampleRate_, + const unsigned int numChannels_, + const int bits, + const StringPairArray& metadataValues) + : AudioFormatWriter (out, + TRANS (wavFormatName), + sampleRate_, + numChannels_, + bits), + lengthInSamples (0), + bytesWritten (0), + writeFailed (false) + { + if (metadataValues.size() > 0) + { + bwavChunk = BWAVChunk::createFrom (metadataValues); + smplChunk = SMPLChunk::createFrom (metadataValues); + } + + headerPosition = out->getPosition(); + writeHeader(); + } + + ~WavAudioFormatWriter() + { + writeHeader(); + } + + bool write (const int** data, int numSamples) + { + jassert (data != 0 && *data != 0); // the input must contain at least one channel! + + if (writeFailed) + return false; + + const int bytes = numChannels * numSamples * bitsPerSample / 8; + tempBlock.ensureSize (bytes, false); + + switch (bitsPerSample) + { + case 8: WriteHelper::write (tempBlock.getData(), numChannels, data, numSamples); break; + case 16: WriteHelper::write (tempBlock.getData(), numChannels, data, numSamples); break; + case 24: WriteHelper::write (tempBlock.getData(), numChannels, data, numSamples); break; + case 32: WriteHelper::write (tempBlock.getData(), numChannels, data, numSamples); break; + default: jassertfalse; break; + } + + if (bytesWritten + bytes >= (uint32) 0xfff00000 + || ! output->write (tempBlock.getData(), bytes)) + { + // failed to write to disk, so let's try writing the header. + // If it's just run out of disk space, then if it does manage + // to write the header, we'll still have a useable file.. + writeHeader(); + writeFailed = true; + return false; + } + else + { + bytesWritten += bytes; + lengthInSamples += numSamples; + + return true; + } + } + + juce_UseDebuggingNewOperator + +private: + ScopedPointer converter; MemoryBlock tempBlock, bwavChunk, smplChunk; uint32 lengthInSamples, bytesWritten; int64 headerPosition; @@ -23667,9 +23200,6 @@ class WavAudioFormatWriter : public AudioFormatWriter static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); } - WavAudioFormatWriter (const WavAudioFormatWriter&); - WavAudioFormatWriter& operator= (const WavAudioFormatWriter&); - void writeHeader() { const bool seekedOk = output->setPosition (headerPosition); @@ -23715,155 +23245,8 @@ class WavAudioFormatWriter : public AudioFormatWriter usesFloatingPointData = (bitsPerSample == 32); } -public: - - WavAudioFormatWriter (OutputStream* const out, - const double sampleRate_, - const unsigned int numChannels_, - const int bits, - const StringPairArray& metadataValues) - : AudioFormatWriter (out, - TRANS (wavFormatName), - sampleRate_, - numChannels_, - bits), - lengthInSamples (0), - bytesWritten (0), - writeFailed (false) - { - if (metadataValues.size() > 0) - { - bwavChunk = BWAVChunk::createFrom (metadataValues); - smplChunk = SMPLChunk::createFrom (metadataValues); - } - - headerPosition = out->getPosition(); - writeHeader(); - } - - ~WavAudioFormatWriter() - { - writeHeader(); - } - - bool write (const int** data, int numSamples) - { - if (writeFailed) - return false; - - const int bytes = numChannels * numSamples * bitsPerSample / 8; - tempBlock.ensureSize (bytes, false); - char* buffer = static_cast (tempBlock.getData()); - - const int* left = data[0]; - const int* right = data[1]; - if (right == 0) - right = left; - - if (bitsPerSample == 16) - { - short* b = (short*) buffer; - - if (numChannels > 1) - { - for (int i = numSamples; --i >= 0;) - { - *b++ = (short) ByteOrder::swapIfBigEndian ((unsigned short) (*left++ >> 16)); - *b++ = (short) ByteOrder::swapIfBigEndian ((unsigned short) (*right++ >> 16)); - } - } - else - { - for (int i = numSamples; --i >= 0;) - { - *b++ = (short) ByteOrder::swapIfBigEndian ((unsigned short) (*left++ >> 16)); - } - } - } - else if (bitsPerSample == 24) - { - char* b = buffer; - - if (numChannels > 1) - { - for (int i = numSamples; --i >= 0;) - { - ByteOrder::littleEndian24BitToChars ((*left++) >> 8, b); - b += 3; - ByteOrder::littleEndian24BitToChars ((*right++) >> 8, b); - b += 3; - } - } - else - { - for (int i = numSamples; --i >= 0;) - { - ByteOrder::littleEndian24BitToChars ((*left++) >> 8, b); - b += 3; - } - } - } - else if (bitsPerSample == 32) - { - unsigned int* b = (unsigned int*) buffer; - - if (numChannels > 1) - { - for (int i = numSamples; --i >= 0;) - { - *b++ = ByteOrder::swapIfBigEndian ((unsigned int) *left++); - *b++ = ByteOrder::swapIfBigEndian ((unsigned int) *right++); - } - } - else - { - for (int i = numSamples; --i >= 0;) - { - *b++ = ByteOrder::swapIfBigEndian ((unsigned int) *left++); - } - } - } - else if (bitsPerSample == 8) - { - unsigned char* b = (unsigned char*) buffer; - - if (numChannels > 1) - { - for (int i = numSamples; --i >= 0;) - { - *b++ = (unsigned char) (128 + (*left++ >> 24)); - *b++ = (unsigned char) (128 + (*right++ >> 24)); - } - } - else - { - for (int i = numSamples; --i >= 0;) - { - *b++ = (unsigned char) (128 + (*left++ >> 24)); - } - } - } - - if (bytesWritten + bytes >= (uint32) 0xfff00000 - || ! output->write (buffer, bytes)) - { - // failed to write to disk, so let's try writing the header. - // If it's just run out of disk space, then if it does manage - // to write the header, we'll still have a useable file.. - writeHeader(); - writeFailed = true; - return false; - } - else - { - bytesWritten += bytes; - lengthInSamples += numSamples; - - return true; - } - } - - juce_UseDebuggingNewOperator + WavAudioFormatWriter (const WavAudioFormatWriter&); + WavAudioFormatWriter& operator= (const WavAudioFormatWriter&); }; WavAudioFormat::WavAudioFormat() @@ -23887,15 +23270,8 @@ const Array WavAudioFormat::getPossibleBitDepths() return Array (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) @@ -27208,7 +26584,6 @@ void AudioDataConverters::deinterleaveSamples (const float* const source, } } -/* #if JUCE_UNIT_TESTS class AudioConversionTests : public UnitTest @@ -27220,6 +26595,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]; @@ -27246,13 +26627,15 @@ public: // convert data from the source to dest format.. ScopedPointer conv (new AudioData::ConverterInstance , AudioData::Pointer >()); - conv->convertSamples (converted, original, numSamples); + conv->convertSamples (inPlace ? reversed : converted, original, numSamples); // ..and back again.. conv = new AudioData::ConverterInstance , AudioData::Pointer >(); - zerostruct (reversed); - conv->convertSamples (reversed, converted, numSamples); + if (! inPlace) + zerostruct (reversed); + + conv->convertSamples (reversed, inPlace ? reversed : converted, numSamples); { int biggestDiff = 0; @@ -27289,11 +26672,12 @@ public: { static void test (UnitTest& unitTest) { + Test3 ::test (unitTest); + Test3 ::test (unitTest); Test3 ::test (unitTest); Test3 ::test (unitTest); Test3 ::test (unitTest); Test3 ::test (unitTest); - Test3 ::test (unitTest); } }; @@ -27322,7 +26706,6 @@ public: static AudioConversionTests audioConversionUnitTests; #endif -*/ END_JUCE_NAMESPACE /*** End of inlined file: juce_AudioDataConverters.cpp ***/ @@ -237978,7 +237361,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) } #endif @@ -238615,7 +237998,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) } class InterProcessLock::Pimpl @@ -248923,11 +248306,16 @@ bool AudioCDBurner::addAudioTrack (AudioSource* audioSource, int numSamples) zeromem (buffer, bytesPerBlock); - AudioDataConverters::convertFloatToInt16LE (sourceBuffer.getSampleData (0, 0), - buffer, samplesPerBlock, 4); + typedef AudioData::Pointer CDSampleFormat; - AudioDataConverters::convertFloatToInt16LE (sourceBuffer.getSampleData (1, 0), - buffer + 2, samplesPerBlock, 4); + typedef AudioData::Pointer 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); @@ -253157,11 +252545,12 @@ public: Array rates; HANDLE clientEvent; BigInteger channels; - AudioDataConverters::DataFormat dataFormat; Array channelMaps; UINT32 actualBufferSize; int bytesPerSample; + virtual void updateFormat (bool isFloat) = 0; + private: const ComSmartPtr createClient() { @@ -253236,10 +252625,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; } @@ -253280,6 +252667,20 @@ public: reservoir.setSize (0); } + void updateFormat (bool isFloat) + { + typedef AudioData::Pointer NativeType; + + if (isFloat) + converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); + else if (bytesPerSample == 4) + converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); + else if (bytesPerSample == 3) + converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); + else + converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); + } + void copyBuffers (float** destBuffers, int numDestBuffers, int bufferSize, Thread& thread) { if (numChannels <= 0) @@ -253294,31 +252695,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; @@ -253348,31 +252725,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; @@ -253393,6 +252746,7 @@ public: ComSmartPtr captureClient; MemoryBlock reservoir; int reservoirSize, reservoirCapacity; + ScopedPointer converter; private: WASAPIInputDevice (const WASAPIInputDevice&); @@ -253424,6 +252778,20 @@ public: renderClient = 0; } + void updateFormat (bool isFloat) + { + typedef AudioData::Pointer NativeType; + + if (isFloat) + converter = new AudioData::ConverterInstance > (1, actualNumChannels); + else if (bytesPerSample == 4) + converter = new AudioData::ConverterInstance > (1, actualNumChannels); + else if (bytesPerSample == 3) + converter = new AudioData::ConverterInstance > (1, actualNumChannels); + else + converter = new AudioData::ConverterInstance > (1, actualNumChannels); + } + void copyBuffers (const float** const srcBuffers, const int numSrcBuffers, int bufferSize, Thread& thread) { if (numChannels <= 0) @@ -253453,31 +252821,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); @@ -253488,6 +252832,7 @@ public: } ComSmartPtr renderClient; + ScopedPointer converter; private: WASAPIOutputDevice (const WASAPIOutputDevice&); @@ -261529,7 +260874,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); @@ -261543,7 +260888,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); @@ -261561,14 +260906,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, @@ -261602,22 +260945,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; } } @@ -261680,48 +261027,44 @@ public: return true; } - 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 (scratch.getData()); - AudioDataConverters::interleaveSamples ((const float**) data, interleaved, numSamples, numChannelsRunning); - AudioDataConverters::convertFloatToFormat (sampleFormat, interleaved, interleaved, numSamples * numChannelsRunning); + for (int i = 0; i < numChannelsRunning; ++i) + converter->convertSamples (scratch.getData(), i, data[i], 0, numSamples); - snd_pcm_sframes_t num = snd_pcm_writei (handle, interleaved, numSamples); - - if (failed (num) && num != -EPIPE && num != -ESTRPIPE) - return false; + numDone = snd_pcm_writei (handle, scratch.getData(), numSamples); } else { for (int i = 0; i < numChannelsRunning; ++i) - if (data[i] != 0) - AudioDataConverters::convertFloatToFormat (sampleFormat, data[i], data[i], numSamples); + converter->convertSamples (data[i], data[i], numSamples); - snd_pcm_sframes_t num = snd_pcm_writen (handle, (void**) data, numSamples); + numDone = snd_pcm_writen (handle, (void**) data, numSamples); + } - if (failed (num)) + if (failed (numDone)) + { + if (numDone == -EPIPE) { - if (num == -EPIPE) - { - if (failed (snd_pcm_prepare (handle))) - return false; - } - else if (num != -ESTRPIPE) + if (failed (snd_pcm_prepare (handle))) return false; } + else if (numDone != -ESTRPIPE) + return false; } return true; } - bool read (AudioSampleBuffer& inputChannelBuffer, const int numSamples) + bool readFromInputDevice (AudioSampleBuffer& inputChannelBuffer, const int numSamples) { jassert (numChannelsRunning <= inputChannelBuffer.getNumChannels()); float** const data = inputChannelBuffer.getArrayOfChannels(); @@ -261729,9 +261072,8 @@ public: if (isInterleaved) { scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false); - float* interleaved = static_cast (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)) { @@ -261744,8 +261086,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 { @@ -261755,8 +261097,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; @@ -261772,7 +261113,47 @@ private: const bool isInput; bool isInterleaved; MemoryBlock scratch; - AudioDataConverters::DataFormat sampleFormat; + ScopedPointer converter; + + template + struct ConverterHelper + { + static AudioData::Converter* createConverter (const bool forInput, const bool isLittleEndian, const int numInterleavedChannels) + { + if (forInput) + { + typedef AudioData::Pointer DestType; + + if (isLittleEndian) + return new AudioData::ConverterInstance , DestType> (numInterleavedChannels, 1); + else + return new AudioData::ConverterInstance , DestType> (numInterleavedChannels, 1); + } + else + { + typedef AudioData::Pointer SourceType; + + if (isLittleEndian) + return new AudioData::ConverterInstance > (1, numInterleavedChannels); + else + return new AudioData::ConverterInstance > (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 ::createConverter (forInput, isLittleEndian, numInterleavedChannels); + case 24: return ConverterHelper ::createConverter (forInput, isLittleEndian, numInterleavedChannels); + case 32: return isFloat ? ConverterHelper ::createConverter (forInput, isLittleEndian, numInterleavedChannels) + : ConverterHelper ::createConverter (forInput, isLittleEndian, numInterleavedChannels); + default: jassertfalse; break; // unsupported format! + } + + return 0; + } bool failed (const int errorNum) { @@ -261963,7 +261344,7 @@ public: { if (inputDevice != 0) { - if (! inputDevice->read (inputChannelBuffer, bufferSize)) + if (! inputDevice->readFromInputDevice (inputChannelBuffer, bufferSize)) { DBG ("ALSA: read failure"); break; @@ -262001,7 +261382,7 @@ public: failed (snd_pcm_avail_update (outputDevice->handle)); - if (! outputDevice->write (outputChannelBuffer, bufferSize)) + if (! outputDevice->writeToOutputDevice (outputChannelBuffer, bufferSize)) { DBG ("ALSA: write failure"); break; @@ -266739,7 +266120,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: @@ -271421,7 +270802,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: @@ -276288,10 +275669,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 CDSampleFormat; + + typedef JUCE_NAMESPACE::AudioData::Pointer 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; } @@ -276865,7 +276255,7 @@ public: JUCEApplication::appWillTerminateByForce(); } - virtual BOOL openFile (const NSString* filename) + virtual BOOL openFile (NSString* filename) { if (JUCEApplication::getInstance() != 0) { @@ -277895,7 +277285,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; diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 7f6aa63f6b..cd01bde8fd 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -64,7 +64,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 69 +#define JUCE_BUILDNUMBER 70 /** Current Juce version number. @@ -337,7 +337,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). @@ -345,7 +345,7 @@ reduce code size. */ #ifndef JUCE_USE_CDREADER - #define JUCE_USE_CDREADER 0 + #define JUCE_USE_CDREADER 1 #endif /** JUCE_USE_CAMERA: Enables web-cam support using the CameraDevice class (Mac and Windows). @@ -427,7 +427,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 @@ -2870,6 +2870,12 @@ public: */ inline operator void*() const throw() { return static_cast (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 (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. @@ -29558,6 +29564,610 @@ private: #ifndef __JUCE_AUDIOFORMATREADER_JUCEHEADER__ #define __JUCE_AUDIOFORMATREADER_JUCEHEADER__ + +/*** Start of inlined file: juce_AudioDataConverters.h ***/ +#ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ +#define __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ + +/** + This class a container which holds all the classes pertaining to the AudioData::Pointer + audio sample format class. + + @see AudioData::Pointer. +*/ +class JUCE_API AudioData +{ +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. */ + class Float32; /**< Used as a template parameter for AudioData::Pointer. Indicates an 32-bit float data format. */ + + // These types can be used as the Endianness template parameter for the AudioData::Pointer class. + + class BigEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in big-endian order. */ + class LittleEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in little-endian order. */ + class NativeEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in the CPU's native endianness. */ + + // These types can be used as the InterleavingType template parameter for the AudioData::Pointer class. + + class NonInterleaved; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored contiguously. */ + class Interleaved; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are interleaved with a number of other channels. */ + + // These types can be used as the Constness template parameter for the AudioData::Pointer class. + + class NonConst; /**< Used as a template parameter for AudioData::Pointer. Indicates that the pointer can be used for non-const data. */ + class Const; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples can only be used for const data.. */ + + /** + A pointer to a block of audio data with a particular encoding. + + This object can be used to read and write from blocks of encoded audio samples. To create one, you specify + the audio format as a series of template parameters, e.g. + @code + // this creates a pointer for reading from a const array of 16-bit little-endian packed samples. + AudioData::Pointer pointer (someRawAudioData); + + // These methods read the sample that is being pointed to + float firstSampleAsFloat = pointer.getAsFloat(); + int32 firstSampleAsInt = pointer.getAsInt32(); + ++pointer; // moves the pointer to the next sample. + pointer += 3; // skips the next 3 samples. + @endcode + + The convertSamples() method lets you copy a range of samples from one format to another, automatically + converting its format. + + @see AudioData::Converter + */ + template + class Pointer : private InterleavingType + { + public: + + /** Creates a non-interleaved pointer from some raw data in the appropriate format. + This constructor is only used if you've specified the AudioData::NonInterleaved option - + for interleaved formats, use the constructor that also takes a number of channels. + */ + Pointer (typename Constness::VoidType* sourceData) throw() + : data (Constness::toVoidPtr (sourceData)) + { + // If you're using 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 pointer from some raw data in the appropriate format with the specified number of interleaved channels. + For non-interleaved data, use the other constructor. + */ + Pointer (typename Constness::VoidType* sourceData, int numInterleavedChannels) throw() + : InterleavingType (numInterleavedChannels), + data (Constness::toVoidPtr (sourceData)) + { + } + + /** Creates a copy of another pointer. */ + Pointer (const Pointer& other) throw() + : InterleavingType (other), + data (other.data) + { + } + + Pointer& operator= (const Pointer& other) throw() + { + data = other.data; + InterleavingType::copyFrom (other); + return *this; + } + + /** Returns the value of the first sample as a floating point value. + The value will be in the range -1.0 to 1.0 for integer formats. For floating point + formats, the value could be outside that range, although -1 to 1 is the standard range. + */ + inline float getAsFloat() const throw() { return Endianness::getAsFloat (data); } + + /** Sets the value of the first sample as a floating point value. + + (This method can only be used if the AudioData::NonConst option was used). + The value should be in the range -1.0 to 1.0 - for integer formats, values outside that + range will be clipped. For floating point formats, any value passed in here will be + written directly, although -1 to 1 is the standard range. + */ + inline void setAsFloat (float newValue) throw() + { + static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! + Endianness::setAsFloat (data, newValue); + } + + /** Returns the value of the first sample as a 32-bit integer. + The value returned will be in the range 0x80000000 to 0x7fffffff, and shorter values will be + shifted to fill this range (e.g. if you're reading from 24-bit data, the values will be shifted up + by 8 bits when returned here). If the source data is floating point, values beyond -1.0 to 1.0 will + be clipped so that -1.0 maps onto -0x7fffffff and 1.0 maps to 0x7fffffff. + */ + inline int32 getAsInt32() const throw() { return Endianness::getAsInt32 (data); } + + /** Sets the value of the first sample as a 32-bit integer. + This will be mapped to the range of the format that is being written - see getAsInt32(). + */ + inline void setAsInt32 (int32 newValue) throw() + { + static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! + Endianness::setAsInt32 (data, newValue); + } + + /** 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; } + + /** Writes a stream of samples into this pointer from another pointer. + This will copy the specified number of samples, converting between formats appropriately. + */ + void convertSamples (Pointer source, int numSamples) const throw() + { + 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) + { + dest.data.copyFromSameType (source.data); + dest.advance(); + source.advance(); + } + } + + /** Writes a stream of samples into this pointer from another pointer. + This will copy the specified number of samples, converting between formats appropriately. + */ + template + void convertSamples (OtherPointerType source, int numSamples) const throw() + { + static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! + + Pointer dest (*this); + + if (source.getRawData() != getRawData() || source.getNumBytesBetweenSamples() >= getNumBytesBetweenSamples()) + { + 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. */ + static bool isFloatingPoint() throw() { return (bool) SampleFormat::isFloat; } + + /** 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, + its resolution is 0x100. + */ + 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; + + inline void advance() throw() { advanceData (data); } + }; + + /** A base class for objects that are used to convert between two different sample formats. + + The AudioData::ConverterInstance implements this base class and can be templated, so + you can create an instance that converts between two particular formats, and then + store this in the abstract base class. + + @see AudioData::ConverterInstance + */ + class Converter + { + 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* destSamples, int destSubChannel, + const void* sourceSamples, int sourceSubChannel, int numSamples) const = 0; + }; + + /** + A class that converts between two templated AudioData::Pointer types, and which + implements the AudioData::Converter interface. + + This can be used as a concrete instance of the AudioData::Converter abstract class. + + @see AudioData::Converter + */ + template + class ConverterInstance : public Converter + { + public: + 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, 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; + }; +}; + +#ifndef DOXYGEN + +class AudioData::BigEndian +{ +public: + template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatBE(); } + template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatBE (newValue); } + template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32BE(); } + template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32BE (newValue); } + template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromBE (source); } + enum { isBigEndian = 1 }; +}; + +class AudioData::LittleEndian +{ +public: + template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatLE(); } + template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatLE (newValue); } + template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32LE(); } + template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32LE (newValue); } + template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromLE (source); } + enum { isBigEndian = 0 }; +}; + +#if JUCE_BIG_ENDIAN + class AudioData::NativeEndian : public AudioData::BigEndian {}; +#else + class AudioData::NativeEndian : public AudioData::LittleEndian {}; +#endif + +class AudioData::Int8 +{ +public: + inline Int8 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + 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 = (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 inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int8& source) throw() { *data = *source.data; } + + int8* data; + enum { bytesPerSample = 1, maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 }; +}; + +class AudioData::UInt8 +{ +public: + inline UInt8 (void* data_) throw() : data (static_cast (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 inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template 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 +{ +public: + inline Int16 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + inline float getAsFloatLE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int16) ByteOrder::swapIfBigEndian (*data)); } + inline float getAsFloatBE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int16) ByteOrder::swapIfLittleEndian (*data)); } + inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) jlimit ((int16) -maxValue, (int16) maxValue, (int16) roundToInt (newValue * (1.0 + maxValue)))); } + inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) jlimit ((int16) -maxValue, (int16) maxValue, (int16) roundToInt (newValue * (1.0 + maxValue)))); } + inline int32 getAsInt32LE() const throw() { return (int32) (ByteOrder::swapIfBigEndian ((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 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 inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int16& source) throw() { *data = *source.data; } + + uint16* data; + enum { bytesPerSample = 2, maxValue = 0x7fff, resolution = (1 << 16), isFloat = 0 }; +}; + +class AudioData::Int24 +{ +public: + inline Int24 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { data += 3; } + inline void skip (int numSamples) throw() { data += 3 * numSamples; } + inline float getAsFloatLE() const throw() { return (float) (ByteOrder::littleEndian24Bit (data) * (1.0 / (1.0 + maxValue))); } + inline float getAsFloatBE() const throw() { return (float) (ByteOrder::bigEndian24Bit (data) * (1.0 / (1.0 + maxValue))); } + inline void setAsFloatLE (float newValue) throw() { ByteOrder::littleEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))), data); } + inline void setAsFloatBE (float newValue) throw() { ByteOrder::bigEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))), data); } + inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::littleEndian24Bit (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 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 inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template 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 { bytesPerSample = 3, maxValue = 0x7fffff, resolution = (1 << 8), isFloat = 0 }; +}; + +class AudioData::Int32 +{ +public: + inline Int32 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + inline float getAsFloatLE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } + inline float getAsFloatBE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } + inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue)))); } + inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue)))); } + inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::swapIfBigEndian (*data); } + 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 inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int32& source) throw() { *data = *source.data; } + + uint32* data; + enum { bytesPerSample = 4, maxValue = 0x7fffffff, resolution = 1, isFloat = 0 }; +}; + +class AudioData::Float32 +{ +public: + inline Float32 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + #if JUCE_BIG_ENDIAN + inline float getAsFloatBE() const throw() { return *data; } + inline void setAsFloatBE (float newValue) throw() { *data = newValue; } + inline float getAsFloatLE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } + inline void setAsFloatLE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } + #else + inline float getAsFloatLE() const throw() { return *data; } + inline void setAsFloatLE (float newValue) throw() { *data = newValue; } + inline float getAsFloatBE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } + inline void setAsFloatBE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } + #endif + inline int32 getAsInt32LE() const throw() { return (int32) roundToInt (jlimit (-1.0f, 1.0f, getAsFloatLE()) * (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 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 inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); } + template inline void copyFromBE (SourceType& source) throw() { setAsFloatBE (source.getAsFloat()); } + inline void copyFromSameType (Float32& source) throw() { *data = *source.data; } + + float* data; + enum { bytesPerSample = 4, maxValue = 0x7fffffff, resolution = (1 << 8), isFloat = 1 }; +}; + +class AudioData::NonInterleaved +{ +public: + inline NonInterleaved() throw() {} + inline NonInterleaved (const NonInterleaved&) throw() {} + inline NonInterleaved (const int) throw() {} + inline void copyFrom (const NonInterleaved&) throw() {} + template inline void advanceData (SampleFormatType& s) throw() { s.advance(); } + template inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numSamples); } + template inline void clear (SampleFormatType& s, int numSamples) throw() { s.clearMultiple (numSamples); } + template inline static int getNumBytesBetweenSamples (const SampleFormatType&) throw() { return SampleFormatType::bytesPerSample; } + + enum { isInterleavedType = 0, numInterleavedChannels = 1 }; +}; + +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 inline void advanceData (SampleFormatType& s) throw() { s.skip (numInterleavedChannels); } + template inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numInterleavedChannels * numSamples); } + template inline void clear (SampleFormatType& s, int numSamples) throw() { while (--numSamples >= 0) { s.clear(); s.skip (numInterleavedChannels); } } + template inline int getNumBytesBetweenSamples (const SampleFormatType& s) const throw() { return numInterleavedChannels * s.bytesPerSample; } + int numInterleavedChannels; + enum { isInterleavedType = 1 }; +}; + +class AudioData::NonConst +{ +public: + typedef void VoidType; + static inline void* toVoidPtr (VoidType* v) throw() { return v; } + enum { isConst = 0 }; +}; + +class AudioData::Const +{ +public: + typedef const void VoidType; + static inline void* toVoidPtr (VoidType* v) throw() { return const_cast (v); } + enum { isConst = 1 }; +}; + +#endif + +/** + A set of routines to convert buffers of 32-bit floating point data to and from + various integer formats. + +*/ +class JUCE_API AudioDataConverters +{ +public: + + static void convertFloatToInt16LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 2); + static void convertFloatToInt16BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 2); + + static void convertFloatToInt24LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 3); + static void convertFloatToInt24BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 3); + + static void convertFloatToInt32LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4); + static void convertFloatToInt32BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4); + + static void convertFloatToFloat32LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4); + static void convertFloatToFloat32BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4); + + static void convertInt16LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 2); + static void convertInt16BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 2); + + static void convertInt24LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 3); + static void convertInt24BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 3); + + static void convertInt32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4); + static void convertInt32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4); + + static void convertFloat32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4); + static void convertFloat32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4); + + enum DataFormat + { + int16LE, + int16BE, + int24LE, + int24BE, + int32LE, + int32BE, + float32LE, + float32BE, + }; + + static void convertFloatToFormat (DataFormat destFormat, + const float* source, void* dest, int numSamples); + + static void convertFormatToFloat (DataFormat sourceFormat, + const void* source, float* dest, int numSamples); + + static void interleaveSamples (const float** source, float* dest, + int numSamples, int numChannels); + + static void deinterleaveSamples (const float* source, float** dest, + int numSamples, int numChannels); + +private: + AudioDataConverters(); + AudioDataConverters (const AudioDataConverters&); + AudioDataConverters& operator= (const AudioDataConverters&); +}; + +#endif // __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ +/*** End of inlined file: juce_AudioDataConverters.h ***/ + class AudioFormat; /** @@ -29739,6 +30349,32 @@ public: juce_UseDebuggingNewOperator +protected: + /** Used by AudioFormatReader subclasses to copy data to different formats. */ + template + struct ReadHelper + { + typedef AudioData::Pointer DestType; + typedef AudioData::Pointer 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; @@ -30412,6 +31048,26 @@ protected: /** The output stream for Use by subclasses. */ OutputStream* output; + /** Used by AudioFormatWriter subclasses to copy data to different formats. */ + template + struct WriteHelper + { + typedef AudioData::Pointer DestType; + typedef AudioData::Pointer 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; @@ -37768,521 +38424,6 @@ private: #endif #ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ -/*** Start of inlined file: juce_AudioDataConverters.h ***/ -#ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ -#define __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ - -#if 0 - -/** - This class a container which holds all the classes pertaining to the AudioData::Pointer - audio sample format class. - - @see AudioData::Pointer. -*/ -class JUCE_API AudioData -{ -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 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. */ - class Float32; /**< Used as a template parameter for AudioData::Pointer. Indicates an 32-bit float data format. */ - - // These types can be used as the Endianness template parameter for the AudioData::Pointer class. - - class BigEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in big-endian order. */ - class LittleEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in little-endian order. */ - class NativeEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in the CPU's native endianness. */ - - // These types can be used as the InterleavingType template parameter for the AudioData::Pointer class. - - class NonInterleaved; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored contiguously. */ - class Interleaved; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are interleaved with a number of other channels. */ - - // These types can be used as the Constness template parameter for the AudioData::Pointer class. - - class NonConst; /**< Used as a template parameter for AudioData::Pointer. Indicates that the pointer can be used for non-const data. */ - class Const; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples can only be used for const data.. */ - - /** - A pointer to a block of audio data with a particular encoding. - - This object can be used to read and write from blocks of encoded audio samples. To create one, you specify - the audio format as a series of template parameters, e.g. - @code - // this creates a pointer for reading from a const array of 16-bit little-endian packed samples. - AudioData::Pointer pointer (someRawAudioData); - - // These methods read the sample that is being pointed to - float firstSampleAsFloat = pointer.getAsFloat(); - int32 firstSampleAsInt = pointer.getAsInt32(); - ++pointer; // moves the pointer to the next sample. - pointer += 3; // skips the next 3 samples. - @endcode - - The convertSamples() method lets you copy a range of samples from one format to another, automatically - converting its format. - - @see AudioData::Converter - */ - template - class Pointer : private InterleavingType - { - public: - - /** Creates a non-interleaved pointer from some raw data in the appropriate format. - This constructor is only used if you've specified the AudioData::NonInterleaved option - - for interleaved formats, use the constructor that also takes a number of channels. - */ - Pointer (typename Constness::VoidType* sourceData) throw() - : data (Constness::toVoidPtr (sourceData)) - { - // If you're using 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 pointer from some raw data in the appropriate format with the specified number of interleaved channels. - For non-interleaved data, use the other constructor. - */ - Pointer (typename Constness::VoidType* sourceData, int numInterleavedChannels) throw() - : 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) - { - } - - Pointer& operator= (const Pointer& other) throw() - { - data = other.data; - return *this; - } - - /** Returns the value of the first sample as a floating point value. - The value will be in the range -1.0 to 1.0 for integer formats. For floating point - formats, the value could be outside that range, although -1 to 1 is the standard range. - */ - inline float getAsFloat() const throw() { return Endianness::getAsFloat (data); } - - /** Sets the value of the first sample as a floating point value. - - (This method can only be used if the AudioData::NonConst option was used). - The value should be in the range -1.0 to 1.0 - for integer formats, values outside that - range will be clipped. For floating point formats, any value passed in here will be - written directly, although -1 to 1 is the standard range. - */ - inline void setAsFloat (float newValue) throw() - { - static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! - Endianness::setAsFloat (data, newValue); - } - - /** Returns the value of the first sample as a 32-bit integer. - The value returned will be in the range 0x80000000 to 0x7fffffff, and shorter values will be - shifted to fill this range (e.g. if you're reading from 24-bit data, the values will be shifted up - by 8 bits when returned here). If the source data is floating point, values beyond -1.0 to 1.0 will - be clipped so that -1.0 maps onto -0x7fffffff and 1.0 maps to 0x7fffffff. - */ - inline int32 getAsInt32() const throw() { return Endianness::getAsInt32 (data); } - - /** Sets the value of the first sample as a 32-bit integer. - This will be mapped to the range of the format that is being written - see getAsInt32(). - */ - inline void setAsInt32 (int32 newValue) throw() - { - static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! - Endianness::setAsInt32 (data, newValue); - } - - /** Adds a number of samples to the pointer's position. */ - inline Pointer& operator++() throw() { advance(); return *this; } - - /** Adds a number of samples to the pointer's position. */ - Pointer& operator+= (int samplesToJump) throw() { advanceDataBy (data, samplesToJump); return *this; } - - /** Writes a stream of samples into this pointer from another pointer. - This will copy the specified number of samples, converting between formats appropriately. - */ - void convertSamples (Pointer source, int numSamples) const throw() - { - 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) - { - dest.data.copyFromSameType (source.data); - dest.advance(); - source.advance(); - } - } - - /** Writes a stream of samples into this pointer from another pointer. - This will copy the specified number of samples, converting between formats appropriately. - */ - template - void convertSamples (OtherPointerType source, int numSamples) const throw() - { - 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) - { - Endianness::copyFrom (dest.data, source); - dest.advance(); - ++source; - } - } - - /** Returns true if the pointer is using a floating-point format. */ - static bool isFloatingPoint() throw() { return (bool) SampleFormat::isFloat; } - - /** Returns true if the format is big-endian. */ - static bool isBigEndian() throw() { return (bool) Endianness::isBigEndian; } - - /** Returns the number of interleaved channels in the format. */ - int getNumInterleavedChannels() const throw() { return (int) this->numInterleavedChannels; } - - /** 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, - its resolution is 0x100. - */ - static int get32BitResolution() throw() { return (int) SampleFormat::resolution; } - - private: - - SampleFormat data; - - inline void advance() throw() { advanceData (data); } - }; - - /** A base class for objects that are used to convert between two different sample formats. - - The AudioData::ConverterInstance implements this base class and can be templated, so - you can create an instance that converts between two particular formats, and then - store this in the abstract base class. - - @see AudioData::ConverterInstance - */ - class Converter - { - public: - virtual ~Converter() {} - - /** - */ - virtual void convertSamples (void* dest, const void* source, int numSamples) const = 0; - }; - - /** - A class that converts between two templated AudioData::Pointer types, and which - implements the AudioData::Converter interface. - - This can be used as a concrete instance of the AudioData::Converter abstract class. - - @see AudioData::Converter - */ - template - class ConverterInstance : public Converter - { - public: - ConverterInstance() {} - ~ConverterInstance() {} - - void convertSamples (void* dest, const void* source, int numSamples) const - { - SourceSampleType s (source); - DestSampleType d (dest); - d.convertSamples (s, numSamples); - } - - private: - ConverterInstance (const ConverterInstance&); - ConverterInstance& operator= (const ConverterInstance&); - }; -}; - -#ifndef DOXYGEN - -class AudioData::BigEndian -{ -public: - template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatBE(); } - template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatBE (newValue); } - template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32BE(); } - template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32BE (newValue); } - template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromBE (source); } - enum { isBigEndian = 1 }; -}; - -class AudioData::LittleEndian -{ -public: - template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatLE(); } - template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatLE (newValue); } - template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32LE(); } - template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32LE (newValue); } - template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromLE (source); } - enum { isBigEndian = 0 }; -}; - -#if JUCE_BIG_ENDIAN - class AudioData::NativeEndian : public AudioData::BigEndian {}; -#else - class AudioData::NativeEndian : public AudioData::LittleEndian {}; -#endif - -class AudioData::Int8 -{ -public: - inline Int8 (void* data_) throw() : data (static_cast (data_)) {} - - inline void advance() throw() { ++data; } - 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 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); } - template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } - template 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 }; -}; - -class AudioData::Int16 -{ -public: - inline Int16 (void* data_) throw() : data (static_cast (data_)) {} - - inline void advance() throw() { ++data; } - inline void skip (int numSamples) throw() { data += numSamples; } - inline float getAsFloatLE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int16) ByteOrder::swapIfBigEndian (*data)); } - inline float getAsFloatBE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int16) ByteOrder::swapIfLittleEndian (*data)); } - inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) jlimit ((int16) -maxValue, (int16) maxValue, (int16) roundToInt (newValue * (1.0 + maxValue)))); } - inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) jlimit ((int16) -maxValue, (int16) maxValue, (int16) roundToInt (newValue * (1.0 + maxValue)))); } - inline int32 getAsInt32LE() const throw() { return (int32) (ByteOrder::swapIfBigEndian ((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 setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) (newValue >> 16)); } - template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } - template 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 }; -}; - -class AudioData::Int24 -{ -public: - inline Int24 (void* data_) throw() : data (static_cast (data_)) {} - - inline void advance() throw() { data += 3; } - inline void skip (int numSamples) throw() { data += 3 * numSamples; } - inline float getAsFloatLE() const throw() { return (float) (ByteOrder::littleEndian24Bit (data) * (1.0 / (1.0 + maxValue))); } - inline float getAsFloatBE() const throw() { return (float) (ByteOrder::bigEndian24Bit (data) * (1.0 / (1.0 + maxValue))); } - inline void setAsFloatLE (float newValue) throw() { ByteOrder::littleEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))), data); } - inline void setAsFloatBE (float newValue) throw() { ByteOrder::bigEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))), data); } - inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::littleEndian24Bit (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 setAsInt32BE (int32 newValue) throw() { ByteOrder::bigEndian24BitToChars (newValue >> 8, data); } - template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } - template 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 }; -}; - -class AudioData::Int32 -{ -public: - inline Int32 (void* data_) throw() : data (static_cast (data_)) {} - - inline void advance() throw() { ++data; } - inline void skip (int numSamples) throw() { data += numSamples; } - inline float getAsFloatLE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } - inline float getAsFloatBE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } - inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue)))); } - inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue)))); } - inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::swapIfBigEndian (*data); } - 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); } - template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } - template 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 }; -}; - -class AudioData::Float32 -{ -public: - inline Float32 (void* data_) throw() : data (static_cast (data_)) {} - - inline void advance() throw() { ++data; } - inline void skip (int numSamples) throw() { data += numSamples; } - #if JUCE_BIG_ENDIAN - inline float getAsFloatBE() const throw() { return *data; } - inline void setAsFloatBE (float newValue) throw() { *data = newValue; } - inline float getAsFloatLE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } - inline void setAsFloatLE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } - #else - inline float getAsFloatLE() const throw() { return *data; } - inline void setAsFloatLE (float newValue) throw() { *data = newValue; } - inline float getAsFloatBE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } - inline void setAsFloatBE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } - #endif - inline int32 getAsInt32LE() const throw() { return (int32) roundToInt (jlimit (-1.0f, 1.0f, getAsFloatLE()) * (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 setAsInt32BE (int32 newValue) throw() { setAsFloatBE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } - template inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); } - template 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 }; -}; - -class AudioData::NonInterleaved -{ -public: - inline NonInterleaved() throw() {} - inline NonInterleaved (const int) throw() {} - template inline void advanceData (SampleFormatType& s) throw() { s.advance(); } - template inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numSamples); } - enum { isInterleavedType = 0, numInterleavedChannels = 1 }; -}; - -class AudioData::Interleaved -{ -public: - inline Interleaved() throw() : numInterleavedChannels (1) {} - inline Interleaved (const int numInterleavedChannels_) throw() : numInterleavedChannels (numInterleavedChannels_) {} - template inline void advanceData (SampleFormatType& s) throw() { s.skip (numInterleavedChannels); } - template inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numInterleavedChannels * numSamples); } - const int numInterleavedChannels; - enum { isInterleavedType = 1 }; - -private: - Interleaved& operator= (const Interleaved&); -}; - -class AudioData::NonConst -{ -public: - typedef void VoidType; - static inline void* toVoidPtr (VoidType* v) throw() { return v; } - enum { isConst = 0 }; -}; - -class AudioData::Const -{ -public: - typedef const void VoidType; - static inline void* toVoidPtr (VoidType* v) throw() { return const_cast (v); } - enum { isConst = 1 }; -}; - -#endif - -#endif - -/** - A set of routines to convert buffers of 32-bit floating point data to and from - various integer formats. - -*/ -class JUCE_API AudioDataConverters -{ -public: - - static void convertFloatToInt16LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 2); - static void convertFloatToInt16BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 2); - - static void convertFloatToInt24LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 3); - static void convertFloatToInt24BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 3); - - static void convertFloatToInt32LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4); - static void convertFloatToInt32BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4); - - static void convertFloatToFloat32LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4); - static void convertFloatToFloat32BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4); - - static void convertInt16LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 2); - static void convertInt16BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 2); - - static void convertInt24LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 3); - static void convertInt24BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 3); - - static void convertInt32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4); - static void convertInt32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4); - - static void convertFloat32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4); - static void convertFloat32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4); - - enum DataFormat - { - int16LE, - int16BE, - int24LE, - int24BE, - int32LE, - int32BE, - float32LE, - float32BE, - }; - - static void convertFloatToFormat (DataFormat destFormat, - const float* source, void* dest, int numSamples); - - static void convertFormatToFloat (DataFormat sourceFormat, - const void* source, float* dest, int numSamples); - - static void interleaveSamples (const float** source, float* dest, - int numSamples, int numChannels); - - static void deinterleaveSamples (const float* source, float** dest, - int numSamples, int numChannels); - -private: - AudioDataConverters(); - AudioDataConverters (const AudioDataConverters&); - AudioDataConverters& operator= (const AudioDataConverters&); -}; - -#endif // __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ -/*** End of inlined file: juce_AudioDataConverters.h ***/ - - #endif #ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ @@ -39692,12 +39833,15 @@ 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, @@ -41113,7 +41257,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. diff --git a/src/audio/audio_file_formats/juce_AiffAudioFormat.cpp b/src/audio/audio_file_formats/juce_AiffAudioFormat.cpp index 2e5dfe2967..84c82f7671 100644 --- a/src/audio/audio_file_formats/juce_AiffAudioFormat.cpp +++ b/src/audio/audio_file_formats/juce_AiffAudioFormat.cpp @@ -32,6 +32,7 @@ BEGIN_JUCE_NAMESPACE #include "../../core/juce_PlatformUtilities.h" #include "../../text/juce_LocalisedStrings.h" + //============================================================================== static const char* const aiffFormatName = "AIFF file"; static const char* const aiffExtensions[] = { ".aiff", ".aif", 0 }; @@ -72,14 +73,14 @@ public: hasGotVer = true; const int ver = input->readIntBigEndian(); - if (ver != 0 && ver != (int)0xa2805140) + if (ver != 0 && ver != (int) 0xa2805140) break; } else if (type == chunkName ("COMM")) { hasGotType = true; - numChannels = (unsigned int)input->readShortBigEndian(); + numChannels = (unsigned int) input->readShortBigEndian(); lengthInSamples = input->readIntBigEndian(); bitsPerSample = input->readShortBigEndian(); bytesPerFrame = (numChannels * bitsPerSample) >> 3; @@ -167,318 +168,42 @@ public: input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame); - const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3) - char tempBuffer [tempBufSize]; - while (numSamples > 0) { - int* left = destSamples[0]; - if (left != 0) - left += startOffsetInDestBuffer; - - int* right = numDestChannels > 1 ? destSamples[1] : 0; - if (right != 0) - right += startOffsetInDestBuffer; + const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3) + char tempBuffer [tempBufSize]; const int numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples); const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame); if (bytesRead < numThisTime * bytesPerFrame) + { + jassert (bytesRead >= 0); zeromem (tempBuffer + bytesRead, numThisTime * bytesPerFrame - bytesRead); + } - if (bitsPerSample == 16) + jassert (! usesFloatingPointData); // (would need to add support for this if it's possible) + + if (littleEndian) { - if (littleEndian) + switch (bitsPerSample) { - const short* src = reinterpret_cast (tempBuffer); - - if (numChannels > 1) - { - if (left == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *right++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - ++src; - } - } - else if (right == 0) - { - for (int i = numThisTime; --i >= 0;) - { - ++src; - *left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - *right++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - } - } - } - else - { - const char* src = tempBuffer; - - if (numChannels > 1) - { - if (left == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *right++ = ByteOrder::bigEndianShort (src) << 16; - src += 4; - } - } - else if (right == 0) - { - for (int i = numThisTime; --i >= 0;) - { - src += 2; - *left++ = ByteOrder::bigEndianShort (src) << 16; - src += 2; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ByteOrder::bigEndianShort (src) << 16; - src += 2; - *right++ = ByteOrder::bigEndianShort (src) << 16; - src += 2; - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ByteOrder::bigEndianShort (src) << 16; - src += 2; - } - } + case 8: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 16: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 24: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 32: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + default: jassertfalse; break; } } - else if (bitsPerSample == 24) + else { - const char* src = tempBuffer; - - if (littleEndian) + switch (bitsPerSample) { - if (numChannels > 1) - { - if (left == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *right++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 6; - } - } - else if (right == 0) - { - for (int i = numThisTime; --i >= 0;) - { - src += 3; - *left++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - *right++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - } - } - } - else - { - if (numChannels > 1) - { - if (left == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *right++ = ByteOrder::bigEndian24Bit (src) << 8; - src += 6; - } - } - else if (right == 0) - { - for (int i = numThisTime; --i >= 0;) - { - src += 3; - *left++ = ByteOrder::bigEndian24Bit (src) << 8; - src += 3; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ByteOrder::bigEndian24Bit (src) << 8; - src += 3; - *right++ = ByteOrder::bigEndian24Bit (src) << 8; - src += 3; - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ByteOrder::bigEndian24Bit (src) << 8; - src += 3; - } - } - } - } - else if (bitsPerSample == 32) - { - const unsigned int* src = reinterpret_cast (tempBuffer); - unsigned int* l = reinterpret_cast (left); - unsigned int* r = reinterpret_cast (right); - - if (littleEndian) - { - if (numChannels > 1) - { - if (l == 0) - { - for (int i = numThisTime; --i >= 0;) - { - ++src; - *r++ = ByteOrder::swapIfBigEndian (*src++); - } - } - else if (r == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *l++ = ByteOrder::swapIfBigEndian (*src++); - ++src; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *l++ = ByteOrder::swapIfBigEndian (*src++); - *r++ = ByteOrder::swapIfBigEndian (*src++); - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *l++ = ByteOrder::swapIfBigEndian (*src++); - } - } - } - else - { - if (numChannels > 1) - { - if (l == 0) - { - for (int i = numThisTime; --i >= 0;) - { - ++src; - *r++ = ByteOrder::swapIfLittleEndian (*src++); - } - } - else if (r == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *l++ = ByteOrder::swapIfLittleEndian (*src++); - ++src; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *l++ = ByteOrder::swapIfLittleEndian (*src++); - *r++ = ByteOrder::swapIfLittleEndian (*src++); - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *l++ = ByteOrder::swapIfLittleEndian (*src++); - } - } - } - - left = reinterpret_cast (l); - right = reinterpret_cast (r); - } - else if (bitsPerSample == 8) - { - const char* src = tempBuffer; - - if (numChannels > 1) - { - if (left == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *right++ = ((int) *src++) << 24; - ++src; - } - } - else if (right == 0) - { - for (int i = numThisTime; --i >= 0;) - { - ++src; - *left++ = ((int) *src++) << 24; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ((int) *src++) << 24; - *right++ = ((int) *src++) << 24; - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ((int) *src++) << 24; - } + case 8: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 16: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 24: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 32: ReadHelper::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::write (tempBlock.getData(), numChannels, data, numSamples); break; + case 16: WriteHelper::write (tempBlock.getData(), numChannels, data, numSamples); break; + case 24: WriteHelper::write (tempBlock.getData(), numChannels, data, numSamples); break; + case 32: WriteHelper::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 (tempBlock.getData()); - - const int* left = data[0]; - const int* right = data[1]; - if (right == 0) - right = left; - - if (bitsPerSample == 16) - { - short* b = reinterpret_cast (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 (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 AiffAudioFormat::getPossibleBitDepths() return Array (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 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; } diff --git a/src/audio/audio_file_formats/juce_AudioFormatReader.h b/src/audio/audio_file_formats/juce_AudioFormatReader.h index 6822f5d4ea..efb53fe341 100644 --- a/src/audio/audio_file_formats/juce_AudioFormatReader.h +++ b/src/audio/audio_file_formats/juce_AudioFormatReader.h @@ -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 + struct ReadHelper + { + typedef AudioData::Pointer DestType; + typedef AudioData::Pointer 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; diff --git a/src/audio/audio_file_formats/juce_AudioFormatWriter.h b/src/audio/audio_file_formats/juce_AudioFormatWriter.h index dad575cd8f..c922dd0299 100644 --- a/src/audio/audio_file_formats/juce_AudioFormatWriter.h +++ b/src/audio/audio_file_formats/juce_AudioFormatWriter.h @@ -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 + struct WriteHelper + { + typedef AudioData::Pointer DestType; + typedef AudioData::Pointer 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; diff --git a/src/audio/audio_file_formats/juce_WavAudioFormat.cpp b/src/audio/audio_file_formats/juce_WavAudioFormat.cpp index 39b6f9053c..d644196f87 100644 --- a/src/audio/audio_file_formats/juce_WavAudioFormat.cpp +++ b/src/audio/audio_file_formats/juce_WavAudioFormat.cpp @@ -38,7 +38,6 @@ BEGIN_JUCE_NAMESPACE static const char* const wavFormatName = "WAV file"; static const char* const wavExtensions[] = { ".wav", ".bwf", 0 }; - //============================================================================== const char* const WavAudioFormat::bwavDescription = "bwav description"; const char* const WavAudioFormat::bwavOriginator = "bwav originator"; @@ -258,17 +257,7 @@ struct ExtensibleWavSubFormat //============================================================================== class WavAudioFormatReader : public AudioFormatReader { - int bytesPerFrame; - int64 dataChunkStart, dataLength; - - static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); } - - WavAudioFormatReader (const WavAudioFormatReader&); - WavAudioFormatReader& operator= (const WavAudioFormatReader&); - public: - int64 bwavChunkStart, bwavSize; - //============================================================================== WavAudioFormatReader (InputStream* const in) : AudioFormatReader (in, TRANS (wavFormatName)), @@ -389,6 +378,7 @@ public: bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int numSamples) { + jassert (destSamples != 0); const int64 samplesAvailable = lengthInSamples - startSampleInFile; if (samplesAvailable < numSamples) @@ -405,212 +395,129 @@ public: input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame); - const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3) - char tempBuffer [tempBufSize]; - while (numSamples > 0) { - int* left = destSamples[0]; - if (left != 0) - left += startOffsetInDestBuffer; - - int* right = numDestChannels > 1 ? destSamples[1] : 0; - if (right != 0) - right += startOffsetInDestBuffer; + const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3) + char tempBuffer [tempBufSize]; const int numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples); const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame); if (bytesRead < numThisTime * bytesPerFrame) + { + jassert (bytesRead >= 0); zeromem (tempBuffer + bytesRead, numThisTime * bytesPerFrame - bytesRead); - - if (bitsPerSample == 16) - { - const short* src = reinterpret_cast (tempBuffer); - - if (numChannels > 1) - { - if (left == 0) - { - for (int i = numThisTime; --i >= 0;) - { - ++src; - *right++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - } - } - else if (right == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - ++src; - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - *right++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - } - } - } - else - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = (int) ByteOrder::swapIfBigEndian ((unsigned short) *src++) << 16; - } - } } - else if (bitsPerSample == 24) + + switch (bitsPerSample) { - const char* src = tempBuffer; - - if (numChannels > 1) - { - if (left == 0) - { - for (int i = numThisTime; --i >= 0;) - { - src += 3; - *right++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - } - } - else if (right == 0) - { - for (int i = numThisTime; --i >= 0;) - { - *left++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 6; - } - } - else - { - for (int i = 0; i < numThisTime; ++i) - { - *left++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - *right++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - } - } - } - else - { - for (int i = 0; i < numThisTime; ++i) - { - *left++ = ByteOrder::littleEndian24Bit (src) << 8; - src += 3; - } - } - } - else if (bitsPerSample == 32) - { - const unsigned int* src = (const unsigned int*) tempBuffer; - unsigned int* l = reinterpret_cast (left); - unsigned int* r = reinterpret_cast (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 (l); - right = reinterpret_cast (r); - } - else if (bitsPerSample == 8) - { - const unsigned char* src = reinterpret_cast (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::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 16: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 24: ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + case 32: if (usesFloatingPointData) ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); + else ReadHelper::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; + default: jassertfalse; break; } startOffsetInDestBuffer += numThisTime; numSamples -= numThisTime; } - if (numSamples > 0) - { - for (int i = numDestChannels; --i >= 0;) - if (destSamples[i] != 0) - zeromem (destSamples[i] + startOffsetInDestBuffer, - sizeof (int) * numSamples); - } - return true; } + int64 bwavChunkStart, bwavSize; + juce_UseDebuggingNewOperator + +private: + ScopedPointer converter; + int bytesPerFrame; + int64 dataChunkStart, dataLength; + + static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); } + + WavAudioFormatReader (const WavAudioFormatReader&); + WavAudioFormatReader& operator= (const WavAudioFormatReader&); }; //============================================================================== class WavAudioFormatWriter : public AudioFormatWriter { +public: + //============================================================================== + WavAudioFormatWriter (OutputStream* const out, + const double sampleRate_, + const unsigned int numChannels_, + const int bits, + const StringPairArray& metadataValues) + : AudioFormatWriter (out, + TRANS (wavFormatName), + sampleRate_, + numChannels_, + bits), + lengthInSamples (0), + bytesWritten (0), + writeFailed (false) + { + if (metadataValues.size() > 0) + { + bwavChunk = BWAVChunk::createFrom (metadataValues); + smplChunk = SMPLChunk::createFrom (metadataValues); + } + + headerPosition = out->getPosition(); + writeHeader(); + } + + ~WavAudioFormatWriter() + { + writeHeader(); + } + + //============================================================================== + bool write (const int** data, int numSamples) + { + jassert (data != 0 && *data != 0); // the input must contain at least one channel! + + if (writeFailed) + return false; + + const int bytes = numChannels * numSamples * bitsPerSample / 8; + tempBlock.ensureSize (bytes, false); + + switch (bitsPerSample) + { + case 8: WriteHelper::write (tempBlock.getData(), numChannels, data, numSamples); break; + case 16: WriteHelper::write (tempBlock.getData(), numChannels, data, numSamples); break; + case 24: WriteHelper::write (tempBlock.getData(), numChannels, data, numSamples); break; + case 32: WriteHelper::write (tempBlock.getData(), numChannels, data, numSamples); break; + default: jassertfalse; break; + } + + if (bytesWritten + bytes >= (uint32) 0xfff00000 + || ! output->write (tempBlock.getData(), bytes)) + { + // failed to write to disk, so let's try writing the header. + // If it's just run out of disk space, then if it does manage + // to write the header, we'll still have a useable file.. + writeHeader(); + writeFailed = true; + return false; + } + else + { + bytesWritten += bytes; + lengthInSamples += numSamples; + + return true; + } + } + + juce_UseDebuggingNewOperator + +private: + ScopedPointer converter; MemoryBlock tempBlock, bwavChunk, smplChunk; uint32 lengthInSamples, bytesWritten; int64 headerPosition; @@ -618,9 +525,6 @@ class WavAudioFormatWriter : public AudioFormatWriter static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); } - WavAudioFormatWriter (const WavAudioFormatWriter&); - WavAudioFormatWriter& operator= (const WavAudioFormatWriter&); - void writeHeader() { const bool seekedOk = output->setPosition (headerPosition); @@ -666,156 +570,8 @@ class WavAudioFormatWriter : public AudioFormatWriter usesFloatingPointData = (bitsPerSample == 32); } -public: - //============================================================================== - WavAudioFormatWriter (OutputStream* const out, - const double sampleRate_, - const unsigned int numChannels_, - const int bits, - const StringPairArray& metadataValues) - : AudioFormatWriter (out, - TRANS (wavFormatName), - sampleRate_, - numChannels_, - bits), - lengthInSamples (0), - bytesWritten (0), - writeFailed (false) - { - if (metadataValues.size() > 0) - { - bwavChunk = BWAVChunk::createFrom (metadataValues); - smplChunk = SMPLChunk::createFrom (metadataValues); - } - - headerPosition = out->getPosition(); - writeHeader(); - } - - ~WavAudioFormatWriter() - { - writeHeader(); - } - - //============================================================================== - bool write (const int** data, int numSamples) - { - if (writeFailed) - return false; - - const int bytes = numChannels * numSamples * bitsPerSample / 8; - tempBlock.ensureSize (bytes, false); - char* buffer = static_cast (tempBlock.getData()); - - const int* left = data[0]; - const int* right = data[1]; - if (right == 0) - right = left; - - if (bitsPerSample == 16) - { - short* b = (short*) buffer; - - if (numChannels > 1) - { - for (int i = numSamples; --i >= 0;) - { - *b++ = (short) ByteOrder::swapIfBigEndian ((unsigned short) (*left++ >> 16)); - *b++ = (short) ByteOrder::swapIfBigEndian ((unsigned short) (*right++ >> 16)); - } - } - else - { - for (int i = numSamples; --i >= 0;) - { - *b++ = (short) ByteOrder::swapIfBigEndian ((unsigned short) (*left++ >> 16)); - } - } - } - else if (bitsPerSample == 24) - { - char* b = buffer; - - if (numChannels > 1) - { - for (int i = numSamples; --i >= 0;) - { - ByteOrder::littleEndian24BitToChars ((*left++) >> 8, b); - b += 3; - ByteOrder::littleEndian24BitToChars ((*right++) >> 8, b); - b += 3; - } - } - else - { - for (int i = numSamples; --i >= 0;) - { - ByteOrder::littleEndian24BitToChars ((*left++) >> 8, b); - b += 3; - } - } - } - else if (bitsPerSample == 32) - { - unsigned int* b = (unsigned int*) buffer; - - if (numChannels > 1) - { - for (int i = numSamples; --i >= 0;) - { - *b++ = ByteOrder::swapIfBigEndian ((unsigned int) *left++); - *b++ = ByteOrder::swapIfBigEndian ((unsigned int) *right++); - } - } - else - { - for (int i = numSamples; --i >= 0;) - { - *b++ = ByteOrder::swapIfBigEndian ((unsigned int) *left++); - } - } - } - else if (bitsPerSample == 8) - { - unsigned char* b = (unsigned char*) buffer; - - if (numChannels > 1) - { - for (int i = numSamples; --i >= 0;) - { - *b++ = (unsigned char) (128 + (*left++ >> 24)); - *b++ = (unsigned char) (128 + (*right++ >> 24)); - } - } - else - { - for (int i = numSamples; --i >= 0;) - { - *b++ = (unsigned char) (128 + (*left++ >> 24)); - } - } - } - - if (bytesWritten + bytes >= (uint32) 0xfff00000 - || ! output->write (buffer, bytes)) - { - // failed to write to disk, so let's try writing the header. - // If it's just run out of disk space, then if it does manage - // to write the header, we'll still have a useable file.. - writeHeader(); - writeFailed = true; - return false; - } - else - { - bytesWritten += bytes; - lengthInSamples += numSamples; - - return true; - } - } - - juce_UseDebuggingNewOperator + WavAudioFormatWriter (const WavAudioFormatWriter&); + WavAudioFormatWriter& operator= (const WavAudioFormatWriter&); }; //============================================================================== @@ -840,15 +596,8 @@ const Array WavAudioFormat::getPossibleBitDepths() return Array (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) diff --git a/src/audio/dsp/juce_AudioDataConverters.cpp b/src/audio/dsp/juce_AudioDataConverters.cpp index a886ca1217..cafb916c3f 100644 --- a/src/audio/dsp/juce_AudioDataConverters.cpp +++ b/src/audio/dsp/juce_AudioDataConverters.cpp @@ -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 conv (new AudioData::ConverterInstance , AudioData::Pointer >()); - conv->convertSamples (converted, original, numSamples); + conv->convertSamples (inPlace ? reversed : converted, original, numSamples); // ..and back again.. conv = new AudioData::ConverterInstance , AudioData::Pointer >(); - 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 ::test (unitTest); + Test3 ::test (unitTest); Test3 ::test (unitTest); Test3 ::test (unitTest); Test3 ::test (unitTest); Test3 ::test (unitTest); - Test3 ::test (unitTest); } }; @@ -648,6 +657,6 @@ public: static AudioConversionTests audioConversionUnitTests; #endif -*/ + END_JUCE_NAMESPACE diff --git a/src/audio/dsp/juce_AudioDataConverters.h b/src/audio/dsp/juce_AudioDataConverters.h index 08a86bd16e..806b7508c7 100644 --- a/src/audio/dsp/juce_AudioDataConverters.h +++ b/src/audio/dsp/juce_AudioDataConverters.h @@ -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 inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } template 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 (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 inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template 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 inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } template 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 inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } template 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 inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } template 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 inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); } template 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 inline void advanceData (SampleFormatType& s) throw() { s.advance(); } - template inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numSamples); } + inline void copyFrom (const NonInterleaved&) throw() {} + template inline void advanceData (SampleFormatType& s) throw() { s.advance(); } + template inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numSamples); } + template inline void clear (SampleFormatType& s, int numSamples) throw() { s.clearMultiple (numSamples); } + template 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 inline void advanceData (SampleFormatType& s) throw() { s.skip (numInterleavedChannels); } template inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numInterleavedChannels * numSamples); } - const int numInterleavedChannels; + template inline void clear (SampleFormatType& s, int numSamples) throw() { while (--numSamples >= 0) { s.clear(); s.skip (numInterleavedChannels); } } + template 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 diff --git a/src/audio/processors/juce_AudioProcessor.h b/src/audio/processors/juce_AudioProcessor.h index b2c3b0ed3b..d64234c0ef 100644 --- a/src/audio/processors/juce_AudioProcessor.h +++ b/src/audio/processors/juce_AudioProcessor.h @@ -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, diff --git a/src/containers/juce_HeapBlock.h b/src/containers/juce_HeapBlock.h index 9b48712bbe..9716bd47ee 100644 --- a/src/containers/juce_HeapBlock.h +++ b/src/containers/juce_HeapBlock.h @@ -122,6 +122,12 @@ public: */ inline operator void*() const throw() { return static_cast (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 (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. diff --git a/src/containers/juce_Variant.cpp b/src/containers/juce_Variant.cpp index 4b3a9f4036..dec3b25991 100644 --- a/src/containers/juce_Variant.cpp +++ b/src/containers/juce_Variant.cpp @@ -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"; } diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index 1e457a2f6e..4c310e63de 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -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. diff --git a/src/gui/components/controls/juce_ListBox.h b/src/gui/components/controls/juce_ListBox.h index b288063d34..c9739fcfe0 100644 --- a/src/gui/components/controls/juce_ListBox.h +++ b/src/gui/components/controls/juce_ListBox.h @@ -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. diff --git a/src/native/linux/juce_linux_Audio.cpp b/src/native/linux/juce_linux_Audio.cpp index 72d8218752..535d219aa1 100644 --- a/src/native/linux/juce_linux_Audio.cpp +++ b/src/native/linux/juce_linux_Audio.cpp @@ -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 (scratch.getData()); - AudioDataConverters::interleaveSamples ((const float**) data, interleaved, numSamples, numChannelsRunning); - AudioDataConverters::convertFloatToFormat (sampleFormat, interleaved, interleaved, numSamples * numChannelsRunning); + for (int i = 0; i < numChannelsRunning; ++i) + converter->convertSamples (scratch.getData(), i, data[i], 0, numSamples); - snd_pcm_sframes_t num = snd_pcm_writei (handle, interleaved, numSamples); - - if (failed (num) && num != -EPIPE && num != -ESTRPIPE) - return false; + numDone = snd_pcm_writei (handle, scratch.getData(), numSamples); } else { for (int i = 0; i < numChannelsRunning; ++i) - if (data[i] != 0) - AudioDataConverters::convertFloatToFormat (sampleFormat, data[i], data[i], numSamples); + converter->convertSamples (data[i], data[i], numSamples); - snd_pcm_sframes_t num = snd_pcm_writen (handle, (void**) data, numSamples); + numDone = snd_pcm_writen (handle, (void**) data, numSamples); + } - if (failed (num)) + if (failed (numDone)) + { + if (numDone == -EPIPE) { - if (num == -EPIPE) - { - if (failed (snd_pcm_prepare (handle))) - return false; - } - else if (num != -ESTRPIPE) + if (failed (snd_pcm_prepare (handle))) return false; } + else if (numDone != -ESTRPIPE) + return false; } return true; } - bool read (AudioSampleBuffer& inputChannelBuffer, const int numSamples) + bool readFromInputDevice (AudioSampleBuffer& inputChannelBuffer, const int numSamples) { jassert (numChannelsRunning <= inputChannelBuffer.getNumChannels()); float** const data = inputChannelBuffer.getArrayOfChannels(); @@ -284,9 +282,8 @@ public: if (isInterleaved) { scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false); - float* interleaved = static_cast (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 converter; + + //============================================================================== + template + struct ConverterHelper + { + static AudioData::Converter* createConverter (const bool forInput, const bool isLittleEndian, const int numInterleavedChannels) + { + if (forInput) + { + typedef AudioData::Pointer DestType; + + if (isLittleEndian) + return new AudioData::ConverterInstance , DestType> (numInterleavedChannels, 1); + else + return new AudioData::ConverterInstance , DestType> (numInterleavedChannels, 1); + } + else + { + typedef AudioData::Pointer SourceType; + + if (isLittleEndian) + return new AudioData::ConverterInstance > (1, numInterleavedChannels); + else + return new AudioData::ConverterInstance > (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 ::createConverter (forInput, isLittleEndian, numInterleavedChannels); + case 24: return ConverterHelper ::createConverter (forInput, isLittleEndian, numInterleavedChannels); + case 32: return isFloat ? ConverterHelper ::createConverter (forInput, isLittleEndian, numInterleavedChannels) + : ConverterHelper ::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; diff --git a/src/native/mac/juce_mac_AudioCDBurner.mm b/src/native/mac/juce_mac_AudioCDBurner.mm index 05580102e0..55db48f5c3 100644 --- a/src/native/mac/juce_mac_AudioCDBurner.mm +++ b/src/native/mac/juce_mac_AudioCDBurner.mm @@ -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 CDSampleFormat; + + typedef JUCE_NAMESPACE::AudioData::Pointer 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; } diff --git a/src/native/mac/juce_mac_CoreAudio.cpp b/src/native/mac/juce_mac_CoreAudio.cpp index 134ed445ce..2b170f38f9 100644 --- a/src/native/mac/juce_mac_CoreAudio.cpp +++ b/src/native/mac/juce_mac_CoreAudio.cpp @@ -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; diff --git a/src/native/mac/juce_mac_Fonts.mm b/src/native/mac/juce_mac_Fonts.mm index 8afbd7c90b..a9ce76abac 100644 --- a/src/native/mac/juce_mac_Fonts.mm +++ b/src/native/mac/juce_mac_Fonts.mm @@ -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: diff --git a/src/native/mac/juce_mac_MessageManager.mm b/src/native/mac/juce_mac_MessageManager.mm index a6bdfa64c5..ed0a3b1483 100644 --- a/src/native/mac/juce_mac_MessageManager.mm +++ b/src/native/mac/juce_mac_MessageManager.mm @@ -82,7 +82,7 @@ public: JUCEApplication::appWillTerminateByForce(); } - virtual BOOL openFile (const NSString* filename) + virtual BOOL openFile (NSString* filename) { if (JUCEApplication::getInstance() != 0) { diff --git a/src/native/windows/juce_win32_AudioCDReader.cpp b/src/native/windows/juce_win32_AudioCDReader.cpp index 260b09e04c..63cde0702e 100644 --- a/src/native/windows/juce_win32_AudioCDReader.cpp +++ b/src/native/windows/juce_win32_AudioCDReader.cpp @@ -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 CDSampleFormat; - AudioDataConverters::convertFloatToInt16LE (sourceBuffer.getSampleData (1, 0), - buffer + 2, samplesPerBlock, 4); + typedef AudioData::Pointer 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); diff --git a/src/native/windows/juce_win32_DynamicLibraryLoader.cpp b/src/native/windows/juce_win32_DynamicLibraryLoader.cpp index 42f8460dac..965f337dbc 100644 --- a/src/native/windows/juce_win32_DynamicLibraryLoader.cpp +++ b/src/native/windows/juce_win32_DynamicLibraryLoader.cpp @@ -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) } diff --git a/src/native/windows/juce_win32_Threads.cpp b/src/native/windows/juce_win32_Threads.cpp index 7b77a561c9..e215549e45 100644 --- a/src/native/windows/juce_win32_Threads.cpp +++ b/src/native/windows/juce_win32_Threads.cpp @@ -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) } diff --git a/src/native/windows/juce_win32_WASAPI.cpp b/src/native/windows/juce_win32_WASAPI.cpp index fdd6802c91..d6565f6c79 100644 --- a/src/native/windows/juce_win32_WASAPI.cpp +++ b/src/native/windows/juce_win32_WASAPI.cpp @@ -232,11 +232,12 @@ public: Array rates; HANDLE clientEvent; BigInteger channels; - AudioDataConverters::DataFormat dataFormat; Array channelMaps; UINT32 actualBufferSize; int bytesPerSample; + virtual void updateFormat (bool isFloat) = 0; + private: const ComSmartPtr 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 NativeType; + + if (isFloat) + converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); + else if (bytesPerSample == 4) + converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); + else if (bytesPerSample == 3) + converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); + else + converter = new AudioData::ConverterInstance , 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 captureClient; MemoryBlock reservoir; int reservoirSize, reservoirCapacity; + ScopedPointer converter; private: WASAPIInputDevice (const WASAPIInputDevice&); @@ -501,6 +467,20 @@ public: renderClient = 0; } + void updateFormat (bool isFloat) + { + typedef AudioData::Pointer NativeType; + + if (isFloat) + converter = new AudioData::ConverterInstance > (1, actualNumChannels); + else if (bytesPerSample == 4) + converter = new AudioData::ConverterInstance > (1, actualNumChannels); + else if (bytesPerSample == 3) + converter = new AudioData::ConverterInstance > (1, actualNumChannels); + else + converter = new AudioData::ConverterInstance > (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 renderClient; + ScopedPointer converter; private: WASAPIOutputDevice (const WASAPIOutputDevice&); diff --git a/src/text/juce_String.cpp b/src/text/juce_String.cpp index 2ff5ecf462..697409f48e 100644 --- a/src/text/juce_String.cpp +++ b/src/text/juce_String.cpp @@ -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 ).decimal_point(); #else static juce_wchar dp = std::use_facet > (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);