@@ -62,9 +62,7 @@ public: | |||||
if (JUCEApplication::getInstance() != 0) | if (JUCEApplication::getInstance() != 0) | ||||
{ | { | ||||
JUCEApplication::getInstance()->systemRequestedQuit(); | JUCEApplication::getInstance()->systemRequestedQuit(); | ||||
if (! MessageManager::getInstance()->hasStopMessageBeenSent()) | |||||
return NSTerminateCancel; | |||||
return NSTerminateCancel; | |||||
} | } | ||||
return NSTerminateNow; | return NSTerminateNow; | ||||
@@ -1,10 +1,11 @@ | |||||
<?xml version="1.0" encoding="Windows-1252"?> | <?xml version="1.0" encoding="Windows-1252"?> | ||||
<VisualStudioProject | <VisualStudioProject | ||||
ProjectType="Visual C++" | ProjectType="Visual C++" | ||||
Version="8.00" | |||||
Version="9.00" | |||||
Name="JUCE" | Name="JUCE" | ||||
ProjectGUID="{AE232C11-D91C-4CA1-B24E-8B11A52EFF26}" | ProjectGUID="{AE232C11-D91C-4CA1-B24E-8B11A52EFF26}" | ||||
RootNamespace="JUCE" | RootNamespace="JUCE" | ||||
TargetFrameworkVersion="131072" | |||||
> | > | ||||
<Platforms> | <Platforms> | ||||
<Platform | <Platform | ||||
@@ -207,6 +208,8 @@ | |||||
AdditionalOptions="/IMPLIB:".\..\..\..\bin\JUCE_debug.lib"
" | AdditionalOptions="/IMPLIB:".\..\..\..\bin\JUCE_debug.lib"
" | ||||
OutputFile="$(OutDir)\$(ProjectName)_debug.dll" | OutputFile="$(OutDir)\$(ProjectName)_debug.dll" | ||||
IgnoreDefaultLibraryNames="libcmt.lib" | IgnoreDefaultLibraryNames="libcmt.lib" | ||||
RandomizedBaseAddress="1" | |||||
DataExecutionPrevention="0" | |||||
/> | /> | ||||
<Tool | <Tool | ||||
Name="VCALinkTool" | Name="VCALinkTool" | ||||
@@ -228,9 +231,6 @@ | |||||
<Tool | <Tool | ||||
Name="VCAppVerifierTool" | Name="VCAppVerifierTool" | ||||
/> | /> | ||||
<Tool | |||||
Name="VCWebDeploymentTool" | |||||
/> | |||||
<Tool | <Tool | ||||
Name="VCPostBuildEventTool" | Name="VCPostBuildEventTool" | ||||
/> | /> | ||||
@@ -289,6 +289,8 @@ | |||||
<Tool | <Tool | ||||
Name="VCLinkerTool" | Name="VCLinkerTool" | ||||
IgnoreDefaultLibraryNames="libcmtd.lib" | IgnoreDefaultLibraryNames="libcmtd.lib" | ||||
RandomizedBaseAddress="1" | |||||
DataExecutionPrevention="0" | |||||
/> | /> | ||||
<Tool | <Tool | ||||
Name="VCALinkTool" | Name="VCALinkTool" | ||||
@@ -310,9 +312,6 @@ | |||||
<Tool | <Tool | ||||
Name="VCAppVerifierTool" | Name="VCAppVerifierTool" | ||||
/> | /> | ||||
<Tool | |||||
Name="VCWebDeploymentTool" | |||||
/> | |||||
<Tool | <Tool | ||||
Name="VCPostBuildEventTool" | Name="VCPostBuildEventTool" | ||||
/> | /> | ||||
@@ -39,6 +39,7 @@ | |||||
#define JUCE_PLUGINHOST_VST 1 | #define JUCE_PLUGINHOST_VST 1 | ||||
#define JUCE_PLUGINHOST_AU 1 | #define JUCE_PLUGINHOST_AU 1 | ||||
#define JUCE_SUPPORT_CARBON 1 | |||||
//#define JUCE_ONLY_BUILD_CORE_LIBRARY 1 | //#define JUCE_ONLY_BUILD_CORE_LIBRARY 1 | ||||
//#define JUCE_FORCE_DEBUG 1 | //#define JUCE_FORCE_DEBUG 1 | ||||
//#define JUCE_LOG_ASSERTIONS 1 | //#define JUCE_LOG_ASSERTIONS 1 | ||||
@@ -2,6 +2,9 @@ | |||||
Microsoft Visual Studio Solution File, Format Version 9.00 | Microsoft Visual Studio Solution File, Format Version 9.00 | ||||
# Visual Studio 2005 | # Visual Studio 2005 | ||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jucedemo", "jucedemo.vcproj", "{050D65C2-17C4-4EE1-ABCE-BEA9DA83D77A}" | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jucedemo", "jucedemo.vcproj", "{050D65C2-17C4-4EE1-ABCE-BEA9DA83D77A}" | ||||
ProjectSection(ProjectDependencies) = postProject | |||||
{AE232C11-D91C-4CA1-B24E-8B11A52EFF26} = {AE232C11-D91C-4CA1-B24E-8B11A52EFF26} | |||||
EndProjectSection | |||||
EndProject | EndProject | ||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JUCE", "..\..\..\..\build\win32\vc8\JUCE.vcproj", "{AE232C11-D91C-4CA1-B24E-8B11A52EFF26}" | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JUCE", "..\..\..\..\build\win32\vc8\JUCE.vcproj", "{AE232C11-D91C-4CA1-B24E-8B11A52EFF26}" | ||||
EndProject | EndProject | ||||
@@ -185,6 +185,16 @@ | |||||
#define JUCE_WEB_BROWSER 1 | #define JUCE_WEB_BROWSER 1 | ||||
#endif | #endif | ||||
//============================================================================= | |||||
/** Setting this allows the build to use old Carbon libraries that will be | |||||
deprecated in newer versions of OSX. This is handy for some backwards-compatibility | |||||
reasons. | |||||
*/ | |||||
#ifndef JUCE_SUPPORT_CARBON | |||||
#define JUCE_SUPPORT_CARBON 1 | |||||
#endif | |||||
//============================================================================= | //============================================================================= | ||||
/* These flags let you avoid the direct inclusion of some 3rd-party libs in the | /* These flags let you avoid the direct inclusion of some 3rd-party libs in the | ||||
codebase - you might need to use this if you're linking to some of these libraries | codebase - you might need to use this if you're linking to some of these libraries | ||||
@@ -221,6 +221,14 @@ | |||||
#define JUCE_WEB_BROWSER 1 | #define JUCE_WEB_BROWSER 1 | ||||
#endif | #endif | ||||
/** Setting this allows the build to use old Carbon libraries that will be | |||||
deprecated in newer versions of OSX. This is handy for some backwards-compatibility | |||||
reasons. | |||||
*/ | |||||
#ifndef JUCE_SUPPORT_CARBON | |||||
#define JUCE_SUPPORT_CARBON 1 | |||||
#endif | |||||
/* These flags let you avoid the direct inclusion of some 3rd-party libs in the | /* These flags let you avoid the direct inclusion of some 3rd-party libs in the | ||||
codebase - you might need to use this if you're linking to some of these libraries | codebase - you might need to use this if you're linking to some of these libraries | ||||
yourself. | yourself. | ||||
@@ -2347,8 +2355,13 @@ public: | |||||
@param destBuffer the place to copy it to; if this is a null pointer, | @param destBuffer the place to copy it to; if this is a null pointer, | ||||
the method just returns the number of bytes required | the method just returns the number of bytes required | ||||
(including the terminating null character). | (including the terminating null character). | ||||
@param maxBufferSizeBytes the size of the destination buffer, in bytes. If the | |||||
string won't fit, it'll put in as many as it can while | |||||
still allowing for a terminating null char at the end, | |||||
and will return the number of bytes that were actually | |||||
used. If this value is < 0, no limit is used. | |||||
*/ | */ | ||||
int copyToUTF8 (uint8* const destBuffer) const throw(); | |||||
int copyToUTF8 (uint8* const destBuffer, const int maxBufferSizeBytes = 0x7fffffff) const throw(); | |||||
/** Returns a pointer to a UTF-8 version of this string. | /** Returns a pointer to a UTF-8 version of this string. | ||||
@@ -36083,11 +36096,13 @@ public: | |||||
This will take care of any floating-point conversion that's required to convert | This will take care of any floating-point conversion that's required to convert | ||||
between the two formats. It won't deal with sample-rate conversion, though. | between the two formats. It won't deal with sample-rate conversion, though. | ||||
If numSamplesToRead < 0, it will write the entire length of the reader. | |||||
@returns false if it can't read or write properly during the operation | @returns false if it can't read or write properly during the operation | ||||
*/ | */ | ||||
bool writeFromAudioReader (AudioFormatReader& reader, | bool writeFromAudioReader (AudioFormatReader& reader, | ||||
int64 startSample, | int64 startSample, | ||||
int numSamplesToRead); | |||||
int64 numSamplesToRead); | |||||
/** Reads some samples from an AudioSource, and writes these to the output. | /** Reads some samples from an AudioSource, and writes these to the output. | ||||
@@ -37229,6 +37244,13 @@ public: | |||||
const StringPairArray& metadataValues, | const StringPairArray& metadataValues, | ||||
int qualityOptionIndex); | int qualityOptionIndex); | ||||
/** Utility function to replace the metadata in a wav file with a new set of values. | |||||
If possible, this cheats by overwriting just the metadata region of the file, rather | |||||
than by copying the whole file again. | |||||
*/ | |||||
bool replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata); | |||||
juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
}; | }; | ||||
@@ -43050,6 +43072,11 @@ public: | |||||
*/ | */ | ||||
virtual int getItemHeight() const { return 20; } | virtual int getItemHeight() const { return 20; } | ||||
/** You can override this method to return false if you don't want to allow the | |||||
user to select this item. | |||||
*/ | |||||
virtual bool canBeSelected() const { return true; } | |||||
/** Creates a component that will be used to represent this item. | /** Creates a component that will be used to represent this item. | ||||
You don't have to implement this method - if it returns 0 then no component | You don't have to implement this method - if it returns 0 then no component | ||||
@@ -66,7 +66,7 @@ | |||||
#pragma warning (disable: 4309 4305) | #pragma warning (disable: 4309 4305) | ||||
#endif | #endif | ||||
#if JUCE_MAC && JUCE_SUPPORT_CARBON | |||||
#if JUCE_MAC && JUCE_32BIT && JUCE_SUPPORT_CARBON | |||||
BEGIN_JUCE_NAMESPACE | BEGIN_JUCE_NAMESPACE | ||||
#include "../build/macosx/platform_specific_code/juce_mac_CarbonViewWrapperComponent.h" | #include "../build/macosx/platform_specific_code/juce_mac_CarbonViewWrapperComponent.h" | ||||
END_JUCE_NAMESPACE | END_JUCE_NAMESPACE | ||||
@@ -330,7 +330,7 @@ AudioFormatWriter::~AudioFormatWriter() | |||||
bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader& reader, | bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader& reader, | ||||
int64 startSample, | int64 startSample, | ||||
int numSamplesToRead) | |||||
int64 numSamplesToRead) | |||||
{ | { | ||||
const int bufferSize = 16384; | const int bufferSize = 16384; | ||||
const int maxChans = 128; | const int maxChans = 128; | ||||
@@ -340,9 +340,12 @@ bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader& reader, | |||||
for (int i = maxChans; --i >= 0;) | for (int i = maxChans; --i >= 0;) | ||||
buffers[i] = 0; | buffers[i] = 0; | ||||
if (numSamplesToRead < 0) | |||||
numSamplesToRead = reader.lengthInSamples; | |||||
while (numSamplesToRead > 0) | while (numSamplesToRead > 0) | ||||
{ | { | ||||
const int numToDo = jmin (numSamplesToRead, bufferSize); | |||||
const int numToDo = (int) jmin (numSamplesToRead, (int64) bufferSize); | |||||
for (int i = tempBuffer.getNumChannels(); --i >= 0;) | for (int i = tempBuffer.getNumChannels(); --i >= 0;) | ||||
buffers[i] = (int*) tempBuffer.getSampleData (i, 0); | buffers[i] = (int*) tempBuffer.getSampleData (i, 0); | ||||
@@ -112,11 +112,13 @@ public: | |||||
This will take care of any floating-point conversion that's required to convert | This will take care of any floating-point conversion that's required to convert | ||||
between the two formats. It won't deal with sample-rate conversion, though. | between the two formats. It won't deal with sample-rate conversion, though. | ||||
If numSamplesToRead < 0, it will write the entire length of the reader. | |||||
@returns false if it can't read or write properly during the operation | @returns false if it can't read or write properly during the operation | ||||
*/ | */ | ||||
bool writeFromAudioReader (AudioFormatReader& reader, | bool writeFromAudioReader (AudioFormatReader& reader, | ||||
int64 startSample, | int64 startSample, | ||||
int numSamplesToRead); | |||||
int64 numSamplesToRead); | |||||
/** Reads some samples from an AudioSource, and writes these to the output. | /** Reads some samples from an AudioSource, and writes these to the output. | ||||
@@ -36,6 +36,8 @@ BEGIN_JUCE_NAMESPACE | |||||
#include "juce_WavAudioFormat.h" | #include "juce_WavAudioFormat.h" | ||||
#include "../../../juce_core/io/streams/juce_BufferedInputStream.h" | #include "../../../juce_core/io/streams/juce_BufferedInputStream.h" | ||||
#include "../../../juce_core/text/juce_LocalisedStrings.h" | #include "../../../juce_core/text/juce_LocalisedStrings.h" | ||||
#include "../../../juce_core/io/files/juce_FileInputStream.h" | |||||
#include "../../../juce_core/io/files/juce_FileOutputStream.h" | |||||
//============================================================================== | //============================================================================== | ||||
@@ -85,55 +87,55 @@ const StringPairArray WavAudioFormat::createBWAVMetadata (const String& descript | |||||
struct BWAVChunk | struct BWAVChunk | ||||
{ | { | ||||
char description [256]; | |||||
char originator [32]; | |||||
char originatorRef [32]; | |||||
char originationDate [10]; | |||||
char originationTime [8]; | |||||
uint8 description [256]; | |||||
uint8 originator [32]; | |||||
uint8 originatorRef [32]; | |||||
uint8 originationDate [10]; | |||||
uint8 originationTime [8]; | |||||
uint32 timeRefLow; | uint32 timeRefLow; | ||||
uint32 timeRefHigh; | uint32 timeRefHigh; | ||||
uint16 version; | uint16 version; | ||||
uint8 umid[64]; | uint8 umid[64]; | ||||
uint8 reserved[190]; | uint8 reserved[190]; | ||||
char codingHistory[1]; | |||||
uint8 codingHistory[1]; | |||||
void copyTo (StringPairArray& values) const | void copyTo (StringPairArray& values) const | ||||
{ | { | ||||
values.set (WavAudioFormat::bwavDescription, String (description, 256)); | |||||
values.set (WavAudioFormat::bwavOriginator, String (originator, 32)); | |||||
values.set (WavAudioFormat::bwavOriginatorRef, String (originatorRef, 32)); | |||||
values.set (WavAudioFormat::bwavOriginationDate, String (originationDate, 10)); | |||||
values.set (WavAudioFormat::bwavOriginationTime, String (originationTime, 8)); | |||||
values.set (WavAudioFormat::bwavDescription, String::fromUTF8 (description, 256)); | |||||
values.set (WavAudioFormat::bwavOriginator, String::fromUTF8 (originator, 32)); | |||||
values.set (WavAudioFormat::bwavOriginatorRef, String::fromUTF8 (originatorRef, 32)); | |||||
values.set (WavAudioFormat::bwavOriginationDate, String::fromUTF8 (originationDate, 10)); | |||||
values.set (WavAudioFormat::bwavOriginationTime, String::fromUTF8 (originationTime, 8)); | |||||
const uint32 timeLow = swapIfBigEndian (timeRefLow); | const uint32 timeLow = swapIfBigEndian (timeRefLow); | ||||
const uint32 timeHigh = swapIfBigEndian (timeRefHigh); | const uint32 timeHigh = swapIfBigEndian (timeRefHigh); | ||||
const int64 time = (((int64)timeHigh) << 32) + timeLow; | const int64 time = (((int64)timeHigh) << 32) + timeLow; | ||||
values.set (WavAudioFormat::bwavTimeReference, String (time)); | values.set (WavAudioFormat::bwavTimeReference, String (time)); | ||||
values.set (WavAudioFormat::bwavCodingHistory, String (codingHistory)); | |||||
values.set (WavAudioFormat::bwavCodingHistory, String::fromUTF8 (codingHistory)); | |||||
} | } | ||||
static MemoryBlock createFrom (const StringPairArray& values) | static MemoryBlock createFrom (const StringPairArray& values) | ||||
{ | { | ||||
const int sizeNeeded = sizeof (BWAVChunk) + values [WavAudioFormat::bwavCodingHistory].length(); | |||||
const int sizeNeeded = sizeof (BWAVChunk) + values [WavAudioFormat::bwavCodingHistory].copyToUTF8 (0) - 1; | |||||
MemoryBlock data ((sizeNeeded + 3) & ~3); | MemoryBlock data ((sizeNeeded + 3) & ~3); | ||||
data.fillWith (0); | data.fillWith (0); | ||||
BWAVChunk* b = (BWAVChunk*) data.getData(); | BWAVChunk* b = (BWAVChunk*) data.getData(); | ||||
// although copyToBuffer may overrun by one byte, that's ok as long as these | |||||
// operations get done in the right order | |||||
values [WavAudioFormat::bwavDescription].copyToBuffer (b->description, 256); | |||||
values [WavAudioFormat::bwavOriginator].copyToBuffer (b->originator, 32); | |||||
values [WavAudioFormat::bwavOriginatorRef].copyToBuffer (b->originatorRef, 32); | |||||
values [WavAudioFormat::bwavOriginationDate].copyToBuffer (b->originationDate, 10); | |||||
values [WavAudioFormat::bwavOriginationTime].copyToBuffer (b->originationTime, 8); | |||||
// Allow these calls to overwrite an extra byte at the end, which is fine as long | |||||
// as they get called in the right order.. | |||||
values [WavAudioFormat::bwavDescription].copyToUTF8 (b->description, 257); | |||||
values [WavAudioFormat::bwavOriginator].copyToUTF8 (b->originator, 33); | |||||
values [WavAudioFormat::bwavOriginatorRef].copyToUTF8 (b->originatorRef, 33); | |||||
values [WavAudioFormat::bwavOriginationDate].copyToUTF8 (b->originationDate, 11); | |||||
values [WavAudioFormat::bwavOriginationTime].copyToUTF8 (b->originationTime, 9); | |||||
const int64 time = values [WavAudioFormat::bwavTimeReference].getLargeIntValue(); | const int64 time = values [WavAudioFormat::bwavTimeReference].getLargeIntValue(); | ||||
b->timeRefLow = swapIfBigEndian ((uint32) (time & 0xffffffff)); | b->timeRefLow = swapIfBigEndian ((uint32) (time & 0xffffffff)); | ||||
b->timeRefHigh = swapIfBigEndian ((uint32) (time >> 32)); | b->timeRefHigh = swapIfBigEndian ((uint32) (time >> 32)); | ||||
values [WavAudioFormat::bwavCodingHistory].copyToBuffer (b->codingHistory, 256 * 1024); | |||||
values [WavAudioFormat::bwavCodingHistory].copyToUTF8 (b->codingHistory); | |||||
if (b->description[0] != 0 | if (b->description[0] != 0 | ||||
|| b->originator[0] != 0 | || b->originator[0] != 0 | ||||
@@ -169,10 +171,14 @@ class WavAudioFormatReader : public AudioFormatReader | |||||
const WavAudioFormatReader& operator= (const WavAudioFormatReader&); | const WavAudioFormatReader& operator= (const WavAudioFormatReader&); | ||||
public: | public: | ||||
int64 bwavChunkStart, bwavSize; | |||||
//============================================================================== | //============================================================================== | ||||
WavAudioFormatReader (InputStream* const in) | WavAudioFormatReader (InputStream* const in) | ||||
: AudioFormatReader (in, wavFormatName), | : AudioFormatReader (in, wavFormatName), | ||||
dataLength (0) | |||||
dataLength (0), | |||||
bwavChunkStart (0), | |||||
bwavSize (0) | |||||
{ | { | ||||
if (input->readInt() == chunkName ("RIFF")) | if (input->readInt() == chunkName ("RIFF")) | ||||
{ | { | ||||
@@ -220,6 +226,9 @@ public: | |||||
} | } | ||||
else if (chunkType == chunkName ("bext")) | else if (chunkType == chunkName ("bext")) | ||||
{ | { | ||||
bwavChunkStart = input->getPosition(); | |||||
bwavSize = length; | |||||
// Broadcast-wav extension chunk.. | // Broadcast-wav extension chunk.. | ||||
BWAVChunk* const bwav = (BWAVChunk*) juce_calloc (jmax (length + 1, (int) sizeof (BWAVChunk))); | BWAVChunk* const bwav = (BWAVChunk*) juce_calloc (jmax (length + 1, (int) sizeof (BWAVChunk))); | ||||
@@ -752,4 +761,82 @@ AudioFormatWriter* WavAudioFormat::createWriterFor (OutputStream* out, | |||||
return 0; | return 0; | ||||
} | } | ||||
static bool juce_slowCopyOfWavFileWithNewMetadata (const File& file, const StringPairArray& metadata) | |||||
{ | |||||
bool ok = false; | |||||
WavAudioFormat wav; | |||||
const File dest (file.getNonexistentSibling()); | |||||
OutputStream* outStream = dest.createOutputStream(); | |||||
if (outStream != 0) | |||||
{ | |||||
AudioFormatReader* reader = wav.createReaderFor (file.createInputStream(), true); | |||||
if (reader != 0) | |||||
{ | |||||
AudioFormatWriter* writer = wav.createWriterFor (outStream, reader->sampleRate, | |||||
reader->numChannels, reader->bitsPerSample, | |||||
metadata, 0); | |||||
if (writer != 0) | |||||
{ | |||||
ok = writer->writeFromAudioReader (*reader, 0, -1); | |||||
outStream = 0; | |||||
delete writer; | |||||
} | |||||
delete reader; | |||||
} | |||||
delete outStream; | |||||
} | |||||
if (ok) | |||||
ok = dest.moveFileTo (file); | |||||
if (! ok) | |||||
dest.deleteFile(); | |||||
return ok; | |||||
} | |||||
bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata) | |||||
{ | |||||
WavAudioFormatReader* reader = (WavAudioFormatReader*) createReaderFor (wavFile.createInputStream(), true); | |||||
if (reader != 0) | |||||
{ | |||||
const int64 bwavPos = reader->bwavChunkStart; | |||||
const int64 bwavSize = reader->bwavSize; | |||||
delete reader; | |||||
if (bwavSize > 0) | |||||
{ | |||||
MemoryBlock chunk = BWAVChunk::createFrom (newMetadata); | |||||
if (chunk.getSize() <= bwavSize) | |||||
{ | |||||
// the new one will fit in the space available, so write it directly.. | |||||
const int64 oldSize = wavFile.getSize(); | |||||
FileOutputStream* out = wavFile.createOutputStream(); | |||||
out->setPosition (bwavPos); | |||||
out->write (chunk.getData(), chunk.getSize()); | |||||
out->setPosition (oldSize); | |||||
delete out; | |||||
jassert (wavFile.getSize() == oldSize); | |||||
return true; | |||||
} | |||||
} | |||||
} | |||||
return juce_slowCopyOfWavFileWithNewMetadata (wavFile, newMetadata); | |||||
} | |||||
END_JUCE_NAMESPACE | END_JUCE_NAMESPACE |
@@ -141,6 +141,13 @@ public: | |||||
const StringPairArray& metadataValues, | const StringPairArray& metadataValues, | ||||
int qualityOptionIndex); | int qualityOptionIndex); | ||||
//============================================================================== | |||||
/** Utility function to replace the metadata in a wav file with a new set of values. | |||||
If possible, this cheats by overwriting just the metadata region of the file, rather | |||||
than by copying the whole file again. | |||||
*/ | |||||
bool replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata); | |||||
//============================================================================== | //============================================================================== | ||||
juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
@@ -37,10 +37,6 @@ | |||||
#include <AudioUnit/AUCocoaUIView.h> | #include <AudioUnit/AUCocoaUIView.h> | ||||
#include <CoreAudioKit/AUGenericView.h> | #include <CoreAudioKit/AUGenericView.h> | ||||
#if JUCE_MAC && JUCE_32BIT | |||||
#define JUCE_SUPPORT_CARBON 1 | |||||
#endif | |||||
#if JUCE_SUPPORT_CARBON | #if JUCE_SUPPORT_CARBON | ||||
#include <AudioToolbox/AudioUnitUtilities.h> | #include <AudioToolbox/AudioUnitUtilities.h> | ||||
#include <AudioUnit/AudioUnitCarbonView.h> | #include <AudioUnit/AudioUnitCarbonView.h> | ||||
@@ -57,6 +53,9 @@ BEGIN_JUCE_NAMESPACE | |||||
#include "../../../../juce_core/misc/juce_PlatformUtilities.h" | #include "../../../../juce_core/misc/juce_PlatformUtilities.h" | ||||
#include "../../../../juce_appframework/gui/components/layout/juce_ComponentMovementWatcher.h" | #include "../../../../juce_appframework/gui/components/layout/juce_ComponentMovementWatcher.h" | ||||
#include "../../../../juce_appframework/gui/components/special/juce_NSViewComponent.h" | #include "../../../../juce_appframework/gui/components/special/juce_NSViewComponent.h" | ||||
#if JUCE_MAC && JUCE_SUPPORT_CARBON | |||||
#include "../../../../../build/macosx/platform_specific_code/juce_mac_CarbonViewWrapperComponent.h" | |||||
#endif | |||||
#if JUCE_MAC | #if JUCE_MAC | ||||
@@ -79,8 +79,10 @@ BEGIN_JUCE_NAMESPACE | |||||
#include "../../../gui/components/layout/juce_ComponentMovementWatcher.h" | #include "../../../gui/components/layout/juce_ComponentMovementWatcher.h" | ||||
#include "../../../application/juce_Application.h" | #include "../../../application/juce_Application.h" | ||||
#include "../../../../juce_core/misc/juce_PlatformUtilities.h" | #include "../../../../juce_core/misc/juce_PlatformUtilities.h" | ||||
#include "../../../../../build/macosx/platform_specific_code/juce_mac_CarbonViewWrapperComponent.h" | |||||
#if JUCE_MAC && JUCE_SUPPORT_CARBON | |||||
#include "../../../../../build/macosx/platform_specific_code/juce_mac_CarbonViewWrapperComponent.h" | |||||
#endif | |||||
//============================================================================== | //============================================================================== | ||||
#undef PRAGMA_ALIGN_SUPPORTED | #undef PRAGMA_ALIGN_SUPPORTED | ||||
@@ -572,6 +572,9 @@ void TreeView::resized() | |||||
void TreeView::moveSelectedRow (int delta) | void TreeView::moveSelectedRow (int delta) | ||||
{ | { | ||||
if (delta == 0) | |||||
return; | |||||
int rowSelected = 0; | int rowSelected = 0; | ||||
TreeViewItem* const firstSelected = getSelectedItem (0); | TreeViewItem* const firstSelected = getSelectedItem (0); | ||||
@@ -580,13 +583,36 @@ void TreeView::moveSelectedRow (int delta) | |||||
rowSelected = jlimit (0, getNumRowsInTree() - 1, rowSelected + delta); | rowSelected = jlimit (0, getNumRowsInTree() - 1, rowSelected + delta); | ||||
TreeViewItem* item = getItemOnRow (rowSelected); | |||||
if (item != 0) | |||||
for (;;) | |||||
{ | { | ||||
item->setSelected (true, true); | |||||
TreeViewItem* item = getItemOnRow (rowSelected); | |||||
if (item != 0) | |||||
{ | |||||
if (! item->canBeSelected()) | |||||
{ | |||||
// if the row we want to highlight doesn't allow it, try skipping | |||||
// to the next item.. | |||||
const int nextRowToTry = jlimit (0, getNumRowsInTree() - 1, | |||||
rowSelected + (delta < 0 ? -1 : 1)); | |||||
scrollToKeepItemVisible (item); | |||||
if (rowSelected != nextRowToTry) | |||||
{ | |||||
rowSelected = nextRowToTry; | |||||
continue; | |||||
} | |||||
else | |||||
{ | |||||
break; | |||||
} | |||||
} | |||||
item->setSelected (true, true); | |||||
scrollToKeepItemVisible (item); | |||||
} | |||||
break; | |||||
} | } | ||||
} | } | ||||
@@ -906,6 +932,9 @@ void TreeViewItem::deselectAllRecursively() | |||||
void TreeViewItem::setSelected (const bool shouldBeSelected, | void TreeViewItem::setSelected (const bool shouldBeSelected, | ||||
const bool deselectOtherItemsFirst) | const bool deselectOtherItemsFirst) | ||||
{ | { | ||||
if (shouldBeSelected && ! canBeSelected()) | |||||
return; | |||||
if (deselectOtherItemsFirst) | if (deselectOtherItemsFirst) | ||||
getTopLevelItem()->deselectAllRecursively(); | getTopLevelItem()->deselectAllRecursively(); | ||||
@@ -238,6 +238,11 @@ public: | |||||
*/ | */ | ||||
virtual int getItemHeight() const { return 20; } | virtual int getItemHeight() const { return 20; } | ||||
/** You can override this method to return false if you don't want to allow the | |||||
user to select this item. | |||||
*/ | |||||
virtual bool canBeSelected() const { return true; } | |||||
/** Creates a component that will be used to represent this item. | /** Creates a component that will be used to represent this item. | ||||
You don't have to implement this method - if it returns 0 then no component | You don't have to implement this method - if it returns 0 then no component | ||||
@@ -150,7 +150,7 @@ PixelARGB* ColourGradient::createLookupTable (int& numEntries) const throw() | |||||
for (int j = 2; j < colours.size(); j += 2) | for (int j = 2; j < colours.size(); j += 2) | ||||
{ | { | ||||
const int numToDo = ((colours.getUnchecked (j) * numEntries) >> 16) - index; | |||||
const int numToDo = ((colours.getUnchecked (j) * (numEntries - 1)) >> 16) - index; | |||||
const PixelARGB pix2 (colours.getUnchecked (j + 1)); | const PixelARGB pix2 (colours.getUnchecked (j + 1)); | ||||
for (int i = 0; i < numToDo; ++i) | for (int i = 0; i < numToDo; ++i) | ||||
@@ -2086,8 +2086,10 @@ const char* String::toUTF8() const throw() | |||||
} | } | ||||
} | } | ||||
int String::copyToUTF8 (uint8* const buffer) const throw() | |||||
int String::copyToUTF8 (uint8* const buffer, const int maxBufferSizeBytes) const throw() | |||||
{ | { | ||||
jassert (maxBufferSizeBytes >= 0); // keep this value positive, or no characters will be copied! | |||||
#if JUCE_STRINGS_ARE_UNICODE | #if JUCE_STRINGS_ARE_UNICODE | ||||
int num = 0, index = 0; | int num = 0, index = 0; | ||||
@@ -2119,10 +2121,18 @@ int String::copyToUTF8 (uint8* const buffer) const throw() | |||||
if (buffer != 0) | if (buffer != 0) | ||||
{ | { | ||||
buffer [num++] = (uint8) ((0xff << (7 - numExtraBytes)) | (c >> (numExtraBytes * 6))); | |||||
if (num + numExtraBytes >= maxBufferSizeBytes) | |||||
{ | |||||
buffer [num++] = 0; | |||||
break; | |||||
} | |||||
else | |||||
{ | |||||
buffer [num++] = (uint8) ((0xff << (7 - numExtraBytes)) | (c >> (numExtraBytes * 6))); | |||||
while (--numExtraBytes >= 0) | |||||
buffer [num++] = (uint8) (0x80 | (0x3f & (c >> (numExtraBytes * 6)))); | |||||
while (--numExtraBytes >= 0) | |||||
buffer [num++] = (uint8) (0x80 | (0x3f & (c >> (numExtraBytes * 6)))); | |||||
} | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -2132,7 +2142,15 @@ int String::copyToUTF8 (uint8* const buffer) const throw() | |||||
else | else | ||||
{ | { | ||||
if (buffer != 0) | if (buffer != 0) | ||||
{ | |||||
if (num + 1 >= maxBufferSizeBytes) | |||||
{ | |||||
buffer [num++] = 0; | |||||
break; | |||||
} | |||||
buffer [num] = (uint8) c; | buffer [num] = (uint8) c; | ||||
} | |||||
++num; | ++num; | ||||
} | } | ||||
@@ -2144,10 +2162,10 @@ int String::copyToUTF8 (uint8* const buffer) const throw() | |||||
return num; | return num; | ||||
#else | #else | ||||
const int numBytes = length() + 1; | |||||
const int numBytes = jmin (maxBufferSizeBytes, length() + 1); | |||||
if (buffer != 0) | if (buffer != 0) | ||||
copyToBuffer ((char*) buffer, numBytes); | |||||
copyToBuffer ((char*) buffer, maxBufferSizeBytes); | |||||
return numBytes; | return numBytes; | ||||
#endif | #endif | ||||
@@ -1003,8 +1003,13 @@ public: | |||||
@param destBuffer the place to copy it to; if this is a null pointer, | @param destBuffer the place to copy it to; if this is a null pointer, | ||||
the method just returns the number of bytes required | the method just returns the number of bytes required | ||||
(including the terminating null character). | (including the terminating null character). | ||||
@param maxBufferSizeBytes the size of the destination buffer, in bytes. If the | |||||
string won't fit, it'll put in as many as it can while | |||||
still allowing for a terminating null char at the end, | |||||
and will return the number of bytes that were actually | |||||
used. If this value is < 0, no limit is used. | |||||
*/ | */ | ||||
int copyToUTF8 (uint8* const destBuffer) const throw(); | |||||
int copyToUTF8 (uint8* const destBuffer, const int maxBufferSizeBytes = 0x7fffffff) const throw(); | |||||
/** Returns a pointer to a UTF-8 version of this string. | /** Returns a pointer to a UTF-8 version of this string. | ||||