@@ -932,7 +932,9 @@ public: | |||||
return namesCopy; | return namesCopy; | ||||
} | } | ||||
const String getDefaultDeviceName (const bool /*preferInputNames*/) const | |||||
const String getDefaultDeviceName (const bool /*preferInputNames*/, | |||||
const int /*numInputChannelsNeeded*/, | |||||
const int /*numOutputChannelsNeeded*/) const | |||||
{ | { | ||||
jassert (hasScanned); // need to call scanForDevices() before doing this | jassert (hasScanned); // need to call scanForDevices() before doing this | ||||
@@ -751,12 +751,12 @@ public: | |||||
int getOutputLatencyInSamples() | int getOutputLatencyInSamples() | ||||
{ | { | ||||
return outputLatency; | |||||
return outputLatency + currentBlockSizeSamples / 4; | |||||
} | } | ||||
int getInputLatencyInSamples() | int getInputLatencyInSamples() | ||||
{ | { | ||||
return inputLatency; | |||||
return inputLatency + currentBlockSizeSamples / 4; | |||||
} | } | ||||
void start (AudioIODeviceCallback* callback) | void start (AudioIODeviceCallback* callback) | ||||
@@ -1809,7 +1809,9 @@ public: | |||||
return deviceNames; | return deviceNames; | ||||
} | } | ||||
const String getDefaultDeviceName (const bool /*preferInputNames*/) const | |||||
const String getDefaultDeviceName (const bool /*preferInputNames*/, | |||||
const int /*numInputChannelsNeeded*/, | |||||
const int /*numOutputChannelsNeeded*/) const | |||||
{ | { | ||||
jassert (hasScanned); // need to call scanForDevices() before doing this | jassert (hasScanned); // need to call scanForDevices() before doing this | ||||
@@ -1477,7 +1477,9 @@ public: | |||||
: outputDeviceNames; | : outputDeviceNames; | ||||
} | } | ||||
const String getDefaultDeviceName (const bool preferInputNames) const | |||||
const String getDefaultDeviceName (const bool preferInputNames, | |||||
const int /*numInputChannelsNeeded*/, | |||||
const int /*numOutputChannelsNeeded*/) const | |||||
{ | { | ||||
jassert (hasScanned); // need to call scanForDevices() before doing this | jassert (hasScanned); // need to call scanForDevices() before doing this | ||||
@@ -11,6 +11,7 @@ Changelist for version 1.46 | |||||
- added AudioUnit support to the audio hosting code | - added AudioUnit support to the audio hosting code | ||||
- any top-level components will now have their parentSizeChanged() method called when the screen res is changed (not on linux yet though..) | - any top-level components will now have their parentSizeChanged() method called when the screen res is changed (not on linux yet though..) | ||||
- jucer: added support for ImageButtons | - jucer: added support for ImageButtons | ||||
- audio devices - a few tweaks to the various audio drivers to try to make the best possible guess at the input and output latencies that they introduce | |||||
============================================================================== | ============================================================================== | ||||
Changelist for version 1.45 | Changelist for version 1.45 | ||||
@@ -118,7 +118,9 @@ const String AudioDeviceManager::initialise (const int numInputChannelsNeeded, | |||||
String defaultDevice; | String defaultDevice; | ||||
if (availableDeviceTypes [0] != 0) | if (availableDeviceTypes [0] != 0) | ||||
defaultDevice = availableDeviceTypes[0]->getDefaultDeviceName (numOutputChannelsNeeded == 0); | |||||
defaultDevice = availableDeviceTypes[0]->getDefaultDeviceName (numOutputChannelsNeeded == 0, | |||||
numInputChannelsNeeded, | |||||
numOutputChannelsNeeded); | |||||
return setAudioDevice (defaultDevice, 0, 0, 0, 0, false); | return setAudioDevice (defaultDevice, 0, 0, 0, 0, false); | ||||
} | } | ||||
@@ -49,10 +49,15 @@ AudioIODeviceType::~AudioIODeviceType() | |||||
//============================================================================== | //============================================================================== | ||||
extern AudioIODeviceType* juce_createDefaultAudioIODeviceType(); | extern AudioIODeviceType* juce_createDefaultAudioIODeviceType(); | ||||
#if JUCE_ASIO && JUCE_WIN32 | |||||
#if JUCE_WIN32 && JUCE_ASIO | |||||
extern AudioIODeviceType* juce_createASIOAudioIODeviceType(); | extern AudioIODeviceType* juce_createASIOAudioIODeviceType(); | ||||
#endif | #endif | ||||
#if JUCE_WIN32 && JUCE_WDM_AUDIO | |||||
extern AudioIODeviceType* juce_createWDMAudioIODeviceType(); | |||||
#endif | |||||
//============================================================================== | |||||
void AudioIODeviceType::createDeviceTypes (OwnedArray <AudioIODeviceType>& list) | void AudioIODeviceType::createDeviceTypes (OwnedArray <AudioIODeviceType>& list) | ||||
{ | { | ||||
AudioIODeviceType* const defaultDeviceType = juce_createDefaultAudioIODeviceType(); | AudioIODeviceType* const defaultDeviceType = juce_createDefaultAudioIODeviceType(); | ||||
@@ -60,9 +65,13 @@ void AudioIODeviceType::createDeviceTypes (OwnedArray <AudioIODeviceType>& list) | |||||
if (defaultDeviceType != 0) | if (defaultDeviceType != 0) | ||||
list.add (defaultDeviceType); | list.add (defaultDeviceType); | ||||
#if JUCE_ASIO && JUCE_WIN32 | |||||
#if JUCE_WIN32 && JUCE_ASIO | |||||
list.add (juce_createASIOAudioIODeviceType()); | list.add (juce_createASIOAudioIODeviceType()); | ||||
#endif | #endif | ||||
#if JUCE_WIN32 && JUCE_WDM_AUDIO | |||||
list.add (juce_createWDMAudioIODeviceType()); | |||||
#endif | |||||
} | } | ||||
@@ -117,8 +117,14 @@ public: | |||||
@param preferInputNames only really used by DirectSound where devices are split up | @param preferInputNames only really used by DirectSound where devices are split up | ||||
into inputs and outputs, this indicates whether to use | into inputs and outputs, this indicates whether to use | ||||
the input or output name to refer to a pair of devices. | the input or output name to refer to a pair of devices. | ||||
@param numInputChannelsNeeded the number of input channels the user is expecting to need - this | |||||
may be used to help decide which device would be most suitable | |||||
@param numOutputChannelsNeeded the number of output channels the user is expecting to need - this | |||||
may be used to help decide which device would be most suitable | |||||
*/ | */ | ||||
virtual const String getDefaultDeviceName (const bool preferInputNames = false) const = 0; | |||||
virtual const String getDefaultDeviceName (const bool preferInputNames, | |||||
const int numInputChannelsNeeded, | |||||
const int numOutputChannelsNeeded) const = 0; | |||||
/** Creates one of the devices of this type. | /** Creates one of the devices of this type. | ||||
@@ -37,25 +37,31 @@ BEGIN_JUCE_NAMESPACE | |||||
//============================================================================== | //============================================================================== | ||||
void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest, int numSamples) | |||||
void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest, int numSamples, const int destBytesPerSample) | |||||
{ | { | ||||
const double maxVal = (double) 0x7fff; | const double maxVal = (double) 0x7fff; | ||||
uint16* const intData = (uint16*) dest; | |||||
char* intData = (char*) dest; | |||||
for (int i = 0; i < numSamples; ++i) | for (int i = 0; i < numSamples; ++i) | ||||
intData[i] = swapIfBigEndian ((uint16) (short) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); | |||||
{ | |||||
*(uint16*)intData = swapIfBigEndian ((uint16) (short) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); | |||||
intData += destBytesPerSample; | |||||
} | |||||
} | } | ||||
void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest, int numSamples) | |||||
void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest, int numSamples, const int destBytesPerSample) | |||||
{ | { | ||||
const double maxVal = (double) 0x7fff; | const double maxVal = (double) 0x7fff; | ||||
uint16* const intData = (uint16*) dest; | |||||
char* intData = (char*) dest; | |||||
for (int i = 0; i < numSamples; ++i) | for (int i = 0; i < numSamples; ++i) | ||||
intData[i] = swapIfLittleEndian ((uint16) (short) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); | |||||
{ | |||||
*(uint16*)intData = swapIfLittleEndian ((uint16) (short) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); | |||||
intData += destBytesPerSample; | |||||
} | |||||
} | } | ||||
void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest, int numSamples) | |||||
void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest, int numSamples, const int destBytesPerSample) | |||||
{ | { | ||||
const double maxVal = (double) 0x7fffff; | const double maxVal = (double) 0x7fffff; | ||||
char* intData = (char*) dest; | char* intData = (char*) dest; | ||||
@@ -63,11 +69,11 @@ void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest | |||||
for (int i = 0; i < numSamples; ++i) | for (int i = 0; i < numSamples; ++i) | ||||
{ | { | ||||
littleEndian24BitToChars ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData); | littleEndian24BitToChars ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData); | ||||
intData += 3; | |||||
intData += destBytesPerSample; | |||||
} | } | ||||
} | } | ||||
void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest, int numSamples) | |||||
void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest, int numSamples, const int destBytesPerSample) | |||||
{ | { | ||||
const double maxVal = (double) 0x7fffff; | const double maxVal = (double) 0x7fffff; | ||||
char* intData = (char*) dest; | char* intData = (char*) dest; | ||||
@@ -75,119 +81,174 @@ void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest | |||||
for (int i = 0; i < numSamples; ++i) | for (int i = 0; i < numSamples; ++i) | ||||
{ | { | ||||
bigEndian24BitToChars ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData); | bigEndian24BitToChars ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData); | ||||
intData += 3; | |||||
intData += destBytesPerSample; | |||||
} | } | ||||
} | } | ||||
void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest, int numSamples) | |||||
void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest, int numSamples, const int destBytesPerSample) | |||||
{ | { | ||||
const double maxVal = (double) 0x7fffffff; | const double maxVal = (double) 0x7fffffff; | ||||
uint32* const intData = (uint32*) dest; | |||||
char* intData = (char*) dest; | |||||
for (int i = 0; i < numSamples; ++i) | for (int i = 0; i < numSamples; ++i) | ||||
intData[i] = swapIfBigEndian ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); | |||||
{ | |||||
*(uint32*)intData = swapIfBigEndian ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); | |||||
intData += destBytesPerSample; | |||||
} | |||||
} | } | ||||
void AudioDataConverters::convertFloatToInt32BE (const float* source, void* dest, int numSamples) | |||||
void AudioDataConverters::convertFloatToInt32BE (const float* source, void* dest, int numSamples, const int destBytesPerSample) | |||||
{ | { | ||||
const double maxVal = (double) 0x7fffffff; | const double maxVal = (double) 0x7fffffff; | ||||
uint32* const intData = (uint32*) dest; | |||||
char* intData = (char*) dest; | |||||
for (int i = 0; i < numSamples; ++i) | for (int i = 0; i < numSamples; ++i) | ||||
intData[i] = swapIfLittleEndian ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); | |||||
{ | |||||
*(uint32*)intData = swapIfLittleEndian ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * source[i]))); | |||||
intData += destBytesPerSample; | |||||
} | |||||
} | } | ||||
void AudioDataConverters::convertFloatToFloat32LE (const float* source, void* dest, int numSamples) | |||||
void AudioDataConverters::convertFloatToFloat32LE (const float* source, void* dest, int numSamples, const int destBytesPerSample) | |||||
{ | { | ||||
if (source != (const float*) dest) | |||||
memcpy (dest, source, numSamples * sizeof (float)); | |||||
#if JUCE_BIG_ENDIAN | |||||
uint32* const data = (uint32*) dest; | |||||
char* d = (char*) dest; | |||||
for (int i = 0; i < numSamples; ++i) | for (int i = 0; i < numSamples; ++i) | ||||
data[i] = swapByteOrder (data [i]); | |||||
{ | |||||
*(float*)d = source[i]; | |||||
#if JUCE_BIG_ENDIAN | |||||
*(uint32*)d = swapByteOrder (*(uint32*)d); | |||||
#endif | #endif | ||||
d += destBytesPerSample; | |||||
} | |||||
} | } | ||||
void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* dest, int numSamples) | |||||
void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* dest, int numSamples, const int destBytesPerSample) | |||||
{ | { | ||||
if (source != (const float*) dest) | |||||
memcpy (dest, source, numSamples * sizeof (float)); | |||||
#if JUCE_LITTLE_ENDIAN | |||||
uint32* const data = (uint32*) dest; | |||||
char* d = (char*) dest; | |||||
for (int i = 0; i < numSamples; ++i) | for (int i = 0; i < numSamples; ++i) | ||||
data[i] = swapByteOrder (data [i]); | |||||
{ | |||||
*(float*)d = source[i]; | |||||
#if JUCE_LITTLE_ENDIAN | |||||
*(uint32*)d = swapByteOrder (*(uint32*)d); | |||||
#endif | #endif | ||||
d += destBytesPerSample; | |||||
} | |||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
void AudioDataConverters::convertInt16LEToFloat (const void* const source, float* const dest, int numSamples) | |||||
void AudioDataConverters::convertInt16LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) | |||||
{ | { | ||||
const float scale = 1.0f / 0x7fff; | const float scale = 1.0f / 0x7fff; | ||||
uint16* const intData = (uint16*) source; | |||||
const char* intData = (const char*) source; | |||||
while (--numSamples >= 0) | |||||
dest [numSamples] = scale * (short) swapIfBigEndian (intData [numSamples]); | |||||
for (int i = 0; i < numSamples; ++i) | |||||
{ | |||||
dest[i] = scale * (short) swapIfBigEndian (*(uint16*)intData); | |||||
intData += srcBytesPerSample; | |||||
} | |||||
} | } | ||||
void AudioDataConverters::convertInt16BEToFloat (const void* const source, float* const dest, int numSamples) | |||||
void AudioDataConverters::convertInt16BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) | |||||
{ | { | ||||
const float scale = 1.0f / 0x7fff; | const float scale = 1.0f / 0x7fff; | ||||
uint16* const intData = (uint16*) source; | |||||
const char* intData = (const char*) source; | |||||
while (--numSamples >= 0) | |||||
dest [numSamples] = scale * (short) swapIfLittleEndian (intData [numSamples]); | |||||
for (int i = 0; i < numSamples; ++i) | |||||
{ | |||||
dest[i] = scale * (short) swapIfLittleEndian (*(uint16*)intData); | |||||
intData += srcBytesPerSample; | |||||
} | |||||
} | } | ||||
void AudioDataConverters::convertInt24LEToFloat (const void* const source, float* const dest, int numSamples) | |||||
void AudioDataConverters::convertInt24LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) | |||||
{ | { | ||||
const float scale = 1.0f / 0x7fffff; | const float scale = 1.0f / 0x7fffff; | ||||
char* const intData = (char*) source; | |||||
const char* intData = (const char*) source; | |||||
while (--numSamples >= 0) | |||||
dest [numSamples] = scale * littleEndian24Bit (intData + (numSamples + numSamples + numSamples)); | |||||
for (int i = 0; i < numSamples; ++i) | |||||
{ | |||||
dest[i] = scale * (short) littleEndian24Bit (intData); | |||||
intData += srcBytesPerSample; | |||||
} | |||||
} | } | ||||
void AudioDataConverters::convertInt24BEToFloat (const void* const source, float* const dest, int numSamples) | |||||
void AudioDataConverters::convertInt24BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) | |||||
{ | { | ||||
const float scale = 1.0f / 0x7fffff; | const float scale = 1.0f / 0x7fffff; | ||||
char* const intData = (char*) source; | |||||
const char* intData = (const char*) source; | |||||
while (--numSamples >= 0) | |||||
dest [numSamples] = scale * bigEndian24Bit (intData + (numSamples + numSamples + numSamples)); | |||||
for (int i = 0; i < numSamples; ++i) | |||||
{ | |||||
dest[i] = scale * (short) bigEndian24Bit (intData); | |||||
intData += srcBytesPerSample; | |||||
} | |||||
} | } | ||||
void AudioDataConverters::convertInt32LEToFloat (const void* const source, float* const dest, int numSamples) | |||||
void AudioDataConverters::convertInt32LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) | |||||
{ | { | ||||
const float scale = 1.0f / 0x7fffffff; | const float scale = 1.0f / 0x7fffffff; | ||||
uint32* const intData = (uint32*) source; | |||||
const char* intData = (const char*) source; | |||||
for (int i = 0; i < numSamples; ++i) | for (int i = 0; i < numSamples; ++i) | ||||
dest [numSamples] = scale * (int) swapIfBigEndian (intData [numSamples]); | |||||
{ | |||||
dest[i] = scale * (int) swapIfBigEndian (*(uint32*) intData); | |||||
intData += srcBytesPerSample; | |||||
} | |||||
} | } | ||||
void AudioDataConverters::convertInt32BEToFloat (const void* const source, float* const dest, int numSamples) | |||||
void AudioDataConverters::convertInt32BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) | |||||
{ | { | ||||
const float scale = 1.0f / 0x7fffffff; | const float scale = 1.0f / 0x7fffffff; | ||||
uint32* const intData = (uint32*) source; | |||||
const char* intData = (const char*) source; | |||||
for (int i = 0; i < numSamples; ++i) | for (int i = 0; i < numSamples; ++i) | ||||
dest [numSamples] = scale * (int) swapIfLittleEndian (intData [numSamples]); | |||||
{ | |||||
dest[i] = scale * (int) (swapIfLittleEndian (*(uint32*) intData)); | |||||
intData += srcBytesPerSample; | |||||
} | |||||
} | } | ||||
void AudioDataConverters::convertFloat32LEToFloat (const void* const source, float* const dest, int numSamples) | |||||
void AudioDataConverters::convertFloat32LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) | |||||
{ | { | ||||
convertFloatToFloat32LE ((float*) source, dest, numSamples); | |||||
const char* s = (const char*) source; | |||||
for (int i = 0; i < numSamples; ++i) | |||||
{ | |||||
dest[i] = *(float*)s; | |||||
#if JUCE_BIG_ENDIAN | |||||
uint32* const d = (uint32*) (dest + i); | |||||
*d = swapByteOrder (*d); | |||||
#endif | |||||
s += srcBytesPerSample; | |||||
} | |||||
} | } | ||||
void AudioDataConverters::convertFloat32BEToFloat (const void* const source, float* const dest, int numSamples) | |||||
void AudioDataConverters::convertFloat32BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample) | |||||
{ | { | ||||
convertFloatToFloat32BE ((float*) source, dest, numSamples); | |||||
const char* s = (const char*) source; | |||||
for (int i = 0; i < numSamples; ++i) | |||||
{ | |||||
dest[i] = *(float*)s; | |||||
#if JUCE_LITTLE_ENDIAN | |||||
uint32* const d = (uint32*) (dest + i); | |||||
*d = swapByteOrder (*d); | |||||
#endif | |||||
s += srcBytesPerSample; | |||||
} | |||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
void AudioDataConverters::convertFloatToFormat (const DataFormat destFormat, | void AudioDataConverters::convertFloatToFormat (const DataFormat destFormat, | ||||
const float* const source, | const float* const source, | ||||
@@ -43,30 +43,30 @@ class JUCE_API AudioDataConverters | |||||
{ | { | ||||
public: | public: | ||||
//============================================================================== | //============================================================================== | ||||
static void convertFloatToInt16LE (const float* source, void* dest, int numSamples); | |||||
static void convertFloatToInt16BE (const float* source, void* dest, int numSamples); | |||||
static void convertFloatToInt16LE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 2); | |||||
static void convertFloatToInt16BE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 2); | |||||
static void convertFloatToInt24LE (const float* source, void* dest, int numSamples); | |||||
static void convertFloatToInt24BE (const float* source, void* dest, int numSamples); | |||||
static void convertFloatToInt24LE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 3); | |||||
static void convertFloatToInt24BE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 3); | |||||
static void convertFloatToInt32LE (const float* source, void* dest, int numSamples); | |||||
static void convertFloatToInt32BE (const float* source, void* dest, int numSamples); | |||||
static void convertFloatToInt32LE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 4); | |||||
static void convertFloatToInt32BE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 4); | |||||
static void convertFloatToFloat32LE (const float* source, void* dest, int numSamples); | |||||
static void convertFloatToFloat32BE (const float* source, void* dest, int numSamples); | |||||
static void convertFloatToFloat32LE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 4); | |||||
static void convertFloatToFloat32BE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 4); | |||||
//============================================================================== | //============================================================================== | ||||
static void convertInt16LEToFloat (const void* source, float* dest, int numSamples); | |||||
static void convertInt16BEToFloat (const void* source, float* dest, int numSamples); | |||||
static void convertInt16LEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 2); | |||||
static void convertInt16BEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 2); | |||||
static void convertInt24LEToFloat (const void* source, float* dest, int numSamples); | |||||
static void convertInt24BEToFloat (const void* source, float* dest, int numSamples); | |||||
static void convertInt24LEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 3); | |||||
static void convertInt24BEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 3); | |||||
static void convertInt32LEToFloat (const void* source, float* dest, int numSamples); | |||||
static void convertInt32BEToFloat (const void* source, float* dest, int numSamples); | |||||
static void convertInt32LEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 4); | |||||
static void convertInt32BEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 4); | |||||
static void convertFloat32LEToFloat (const void* source, float* dest, int numSamples); | |||||
static void convertFloat32BEToFloat (const void* source, float* dest, int numSamples); | |||||
static void convertFloat32LEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 4); | |||||
static void convertFloat32BEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 4); | |||||
//============================================================================== | //============================================================================== | ||||
enum DataFormat | enum DataFormat | ||||
@@ -132,14 +132,8 @@ FileBrowserComponent::FileBrowserComponent (FileChooserMode mode_, | |||||
addAndMakeVisible (label); | addAndMakeVisible (label); | ||||
label->attachToComponent (filenameBox, true); | label->attachToComponent (filenameBox, true); | ||||
addAndMakeVisible (goUpButton = new DrawableButton ("up", DrawableButton::ImageOnButtonBackground)); | |||||
Path arrowPath; | |||||
arrowPath.addArrow (50.0f, 100.0f, 50.0f, 0.0, 40.0f, 100.0f, 50.0f); | |||||
DrawablePath arrowImage; | |||||
arrowImage.setSolidFill (Colours::black.withAlpha (0.4f)); | |||||
arrowImage.setPath (arrowPath); | |||||
goUpButton->setImages (&arrowImage); | |||||
addAndMakeVisible (goUpButton = getLookAndFeel().createFileBrowserGoUpButton()); | |||||
goUpButton->addButtonListener (this); | goUpButton->addButtonListener (this); | ||||
goUpButton->setTooltip (TRANS ("go up to parent directory")); | goUpButton->setTooltip (TRANS ("go up to parent directory")); | ||||
@@ -275,33 +269,10 @@ FilePreviewComponent* FileBrowserComponent::getPreviewComponent() const throw() | |||||
//============================================================================== | //============================================================================== | ||||
void FileBrowserComponent::resized() | void FileBrowserComponent::resized() | ||||
{ | { | ||||
const int x = 8; | |||||
int w = getWidth() - x - x; | |||||
if (previewComp != 0) | |||||
{ | |||||
const int previewWidth = w / 3; | |||||
previewComp->setBounds (x + w - previewWidth, 0, previewWidth, getHeight()); | |||||
w -= previewWidth + 4; | |||||
} | |||||
int y = 4; | |||||
const int controlsHeight = 22; | |||||
const int bottomSectionHeight = controlsHeight + 8; | |||||
const int upButtonWidth = 50; | |||||
currentPathBox->setBounds (x, y, w - upButtonWidth - 6, controlsHeight); | |||||
goUpButton->setBounds (x + w - upButtonWidth, y, upButtonWidth, controlsHeight); | |||||
y += controlsHeight + 4; | |||||
Component* const listAsComp = dynamic_cast <Component*> (fileListComponent); | |||||
listAsComp->setBounds (x, y, w, getHeight() - y - bottomSectionHeight); | |||||
y = listAsComp->getBottom() + 4; | |||||
filenameBox->setBounds (x + 50, y, w - 50, controlsHeight); | |||||
getLookAndFeel() | |||||
.layoutFileBrowserComponent (*this, fileListComponent, | |||||
previewComp, currentPathBox, | |||||
filenameBox, goUpButton); | |||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
@@ -200,7 +200,7 @@ private: | |||||
FilePreviewComponent* previewComp; | FilePreviewComponent* previewComp; | ||||
ComboBox* currentPathBox; | ComboBox* currentPathBox; | ||||
TextEditor* filenameBox; | TextEditor* filenameBox; | ||||
DrawableButton* goUpButton; | |||||
Button* goUpButton; | |||||
TimeSliceThread thread; | TimeSliceThread thread; | ||||
@@ -39,8 +39,6 @@ BEGIN_JUCE_NAMESPACE | |||||
//============================================================================== | //============================================================================== | ||||
const int spaceAroundImage = 4; | |||||
TabBarButton::TabBarButton (const String& name, | TabBarButton::TabBarButton (const String& name, | ||||
TabbedButtonBar* const owner_, | TabbedButtonBar* const owner_, | ||||
const int index) | const int index) | ||||
@@ -128,6 +126,8 @@ void TabBarButton::getActiveArea (int& x, int& y, int& w, int& h) | |||||
int r = getWidth(); | int r = getWidth(); | ||||
int b = getHeight(); | int b = getHeight(); | ||||
const int spaceAroundImage = getLookAndFeel().getTabButtonSpaceAroundImage(); | |||||
if (owner->getOrientation() != TabbedButtonBar::TabsAtLeft) | if (owner->getOrientation() != TabbedButtonBar::TabsAtLeft) | ||||
r -= spaceAroundImage; | r -= spaceAroundImage; | ||||
@@ -377,7 +377,8 @@ void TabbedButtonBar::resized() | |||||
if (orientation == TabsAtTop || orientation == TabsAtBottom) | if (orientation == TabsAtTop || orientation == TabsAtBottom) | ||||
swapVariables (depth, length); | swapVariables (depth, length); | ||||
const int overlap = getLookAndFeel().getTabButtonOverlap (depth) + spaceAroundImage * 2; | |||||
const int overlap = getLookAndFeel().getTabButtonOverlap (depth) | |||||
+ getLookAndFeel().getTabButtonSpaceAroundImage() * 2; | |||||
int i, totalLength = overlap; | int i, totalLength = overlap; | ||||
int numVisibleButtons = tabs.size(); | int numVisibleButtons = tabs.size(); | ||||
@@ -57,6 +57,7 @@ BEGIN_JUCE_NAMESPACE | |||||
#include "../filebrowser/juce_FilenameComponent.h" | #include "../filebrowser/juce_FilenameComponent.h" | ||||
#include "../filebrowser/juce_DirectoryContentsDisplayComponent.h" | #include "../filebrowser/juce_DirectoryContentsDisplayComponent.h" | ||||
#include "../filebrowser/juce_FileSearchPathListComponent.h" | #include "../filebrowser/juce_FileSearchPathListComponent.h" | ||||
#include "../filebrowser/juce_FileBrowserComponent.h" | |||||
#include "../layout/juce_GroupComponent.h" | #include "../layout/juce_GroupComponent.h" | ||||
#include "../properties/juce_PropertyComponent.h" | #include "../properties/juce_PropertyComponent.h" | ||||
#include "../juce_Desktop.h" | #include "../juce_Desktop.h" | ||||
@@ -1790,6 +1791,11 @@ int LookAndFeel::getTabButtonOverlap (int tabDepth) | |||||
return 1 + tabDepth / 3; | return 1 + tabDepth / 3; | ||||
} | } | ||||
int LookAndFeel::getTabButtonSpaceAroundImage() | |||||
{ | |||||
return 4; | |||||
} | |||||
void LookAndFeel::createTabButtonShape (Path& p, | void LookAndFeel::createTabButtonShape (Path& p, | ||||
int width, int height, | int width, int height, | ||||
int /*tabIndex*/, | int /*tabIndex*/, | ||||
@@ -2323,6 +2329,58 @@ void LookAndFeel::drawFileBrowserRow (Graphics& g, int width, int height, | |||||
} | } | ||||
} | } | ||||
Button* LookAndFeel::createFileBrowserGoUpButton() | |||||
{ | |||||
DrawableButton* goUpButton = new DrawableButton ("up", DrawableButton::ImageOnButtonBackground); | |||||
Path arrowPath; | |||||
arrowPath.addArrow (50.0f, 100.0f, 50.0f, 0.0, 40.0f, 100.0f, 50.0f); | |||||
DrawablePath arrowImage; | |||||
arrowImage.setSolidFill (Colours::black.withAlpha (0.4f)); | |||||
arrowImage.setPath (arrowPath); | |||||
goUpButton->setImages (&arrowImage); | |||||
return goUpButton; | |||||
} | |||||
void LookAndFeel::layoutFileBrowserComponent (FileBrowserComponent& browserComp, | |||||
DirectoryContentsDisplayComponent* fileListComponent, | |||||
FilePreviewComponent* previewComp, | |||||
ComboBox* currentPathBox, | |||||
TextEditor* filenameBox, | |||||
Button* goUpButton) | |||||
{ | |||||
const int x = 8; | |||||
int w = browserComp.getWidth() - x - x; | |||||
if (previewComp != 0) | |||||
{ | |||||
const int previewWidth = w / 3; | |||||
previewComp->setBounds (x + w - previewWidth, 0, previewWidth, browserComp.getHeight()); | |||||
w -= previewWidth + 4; | |||||
} | |||||
int y = 4; | |||||
const int controlsHeight = 22; | |||||
const int bottomSectionHeight = controlsHeight + 8; | |||||
const int upButtonWidth = 50; | |||||
currentPathBox->setBounds (x, y, w - upButtonWidth - 6, controlsHeight); | |||||
goUpButton->setBounds (x + w - upButtonWidth, y, upButtonWidth, controlsHeight); | |||||
y += controlsHeight + 4; | |||||
Component* const listAsComp = dynamic_cast <Component*> (fileListComponent); | |||||
listAsComp->setBounds (x, y, w, browserComp.getHeight() - y - bottomSectionHeight); | |||||
y = listAsComp->getBottom() + 4; | |||||
filenameBox->setBounds (x + 50, y, w - 50, controlsHeight); | |||||
} | |||||
Image* LookAndFeel::getDefaultFolderImage() | Image* LookAndFeel::getDefaultFolderImage() | ||||
{ | { | ||||
static const unsigned char foldericon_png[] = { 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,28,8,6,0,0,0,0,194,189,34,0,0,0,4,103,65,77,65,0,0,175,200,55,5, | static const unsigned char foldericon_png[] = { 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,28,8,6,0,0,0,0,194,189,34,0,0,0,4,103,65,77,65,0,0,175,200,55,5, | ||||
@@ -58,6 +58,9 @@ class Toolbar; | |||||
class ToolbarItemComponent; | class ToolbarItemComponent; | ||||
class PopupMenu; | class PopupMenu; | ||||
class ProgressBar; | class ProgressBar; | ||||
class FileBrowserComponent; | |||||
class DirectoryContentsDisplayComponent; | |||||
class FilePreviewComponent; | |||||
//============================================================================== | //============================================================================== | ||||
@@ -262,6 +265,15 @@ public: | |||||
const bool isDirectory, | const bool isDirectory, | ||||
const bool isItemSelected); | const bool isItemSelected); | ||||
virtual Button* createFileBrowserGoUpButton(); | |||||
virtual void layoutFileBrowserComponent (FileBrowserComponent& browserComp, | |||||
DirectoryContentsDisplayComponent* fileListComponent, | |||||
FilePreviewComponent* previewComp, | |||||
ComboBox* currentPathBox, | |||||
TextEditor* filenameBox, | |||||
Button* goUpButton); | |||||
//============================================================================== | //============================================================================== | ||||
virtual void drawBubble (Graphics& g, | virtual void drawBubble (Graphics& g, | ||||
float tipX, float tipY, | float tipX, float tipY, | ||||
@@ -449,6 +461,7 @@ public: | |||||
const bool isFrontTab); | const bool isFrontTab); | ||||
virtual int getTabButtonOverlap (int tabDepth); | virtual int getTabButtonOverlap (int tabDepth); | ||||
virtual int getTabButtonSpaceAroundImage(); | |||||
virtual int getTabButtonBestWidth (int tabIndex, | virtual int getTabButtonBestWidth (int tabIndex, | ||||
const String& text, | const String& text, | ||||
@@ -361,7 +361,6 @@ public: | |||||
if (menu.items.size() > 0) | if (menu.items.size() > 0) | ||||
{ | { | ||||
int totalItems = 0; | int totalItems = 0; | ||||
bool lastItemWasSeparator = true; | |||||
PopupMenuWindow* const mw = new PopupMenuWindow(); | PopupMenuWindow* const mw = new PopupMenuWindow(); | ||||
mw->setLookAndFeel (menu.lookAndFeel); | mw->setLookAndFeel (menu.lookAndFeel); | ||||
@@ -375,30 +374,8 @@ public: | |||||
{ | { | ||||
MenuItemInfo* const item = (MenuItemInfo*) menu.items.getUnchecked(i); | MenuItemInfo* const item = (MenuItemInfo*) menu.items.getUnchecked(i); | ||||
if (item->isSeparator) | |||||
{ | |||||
if (! lastItemWasSeparator) | |||||
{ | |||||
// check it's not one of the last separators.. | |||||
for (int j = i + 1; j < menu.items.size(); ++j) | |||||
{ | |||||
if (! ((MenuItemInfo*) menu.items.getUnchecked (j))->isSeparator) | |||||
{ | |||||
mw->addItem (*item); | |||||
++totalItems; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
mw->addItem (*item); | |||||
++totalItems; | |||||
} | |||||
lastItemWasSeparator = item->isSeparator; | |||||
mw->addItem (*item); | |||||
++totalItems; | |||||
} | } | ||||
if (totalItems == 0) | if (totalItems == 0) | ||||
@@ -1321,13 +1298,15 @@ private: | |||||
//============================================================================== | //============================================================================== | ||||
PopupMenu::PopupMenu() throw() | PopupMenu::PopupMenu() throw() | ||||
: items (8), | : items (8), | ||||
lookAndFeel (0) | |||||
lookAndFeel (0), | |||||
separatorPending (false) | |||||
{ | { | ||||
} | } | ||||
PopupMenu::PopupMenu (const PopupMenu& other) throw() | PopupMenu::PopupMenu (const PopupMenu& other) throw() | ||||
: items (8), | : items (8), | ||||
lookAndFeel (other.lookAndFeel) | |||||
lookAndFeel (other.lookAndFeel), | |||||
separatorPending (false) | |||||
{ | { | ||||
items.ensureStorageAllocated (other.items.size()); | items.ensureStorageAllocated (other.items.size()); | ||||
@@ -1365,6 +1344,18 @@ void PopupMenu::clear() throw() | |||||
} | } | ||||
items.clear(); | items.clear(); | ||||
separatorPending = false; | |||||
} | |||||
void PopupMenu::addSeparatorIfPending() | |||||
{ | |||||
if (separatorPending) | |||||
{ | |||||
separatorPending = false; | |||||
if (items.size() > 0) | |||||
items.add (new MenuItemInfo()); | |||||
} | |||||
} | } | ||||
void PopupMenu::addItem (const int itemResultId, | void PopupMenu::addItem (const int itemResultId, | ||||
@@ -1377,6 +1368,8 @@ void PopupMenu::addItem (const int itemResultId, | |||||
// didn't pick anything, so you shouldn't use it as the id | // didn't pick anything, so you shouldn't use it as the id | ||||
// for an item.. | // for an item.. | ||||
addSeparatorIfPending(); | |||||
items.add (new MenuItemInfo (itemResultId, | items.add (new MenuItemInfo (itemResultId, | ||||
itemText, | itemText, | ||||
isActive, | isActive, | ||||
@@ -1400,6 +1393,8 @@ void PopupMenu::addCommandItem (ApplicationCommandManager* commandManager, | |||||
ApplicationCommandInfo info (*registeredInfo); | ApplicationCommandInfo info (*registeredInfo); | ||||
ApplicationCommandTarget* const target = commandManager->getTargetForCommand (commandID, info); | ApplicationCommandTarget* const target = commandManager->getTargetForCommand (commandID, info); | ||||
addSeparatorIfPending(); | |||||
items.add (new MenuItemInfo (commandID, | items.add (new MenuItemInfo (commandID, | ||||
displayName.isNotEmpty() ? displayName | displayName.isNotEmpty() ? displayName | ||||
: info.shortName, | : info.shortName, | ||||
@@ -1424,6 +1419,8 @@ void PopupMenu::addColouredItem (const int itemResultId, | |||||
// didn't pick anything, so you shouldn't use it as the id | // didn't pick anything, so you shouldn't use it as the id | ||||
// for an item.. | // for an item.. | ||||
addSeparatorIfPending(); | |||||
items.add (new MenuItemInfo (itemResultId, | items.add (new MenuItemInfo (itemResultId, | ||||
itemText, | itemText, | ||||
isActive, | isActive, | ||||
@@ -1442,6 +1439,8 @@ void PopupMenu::addCustomItem (const int itemResultId, | |||||
// didn't pick anything, so you shouldn't use it as the id | // didn't pick anything, so you shouldn't use it as the id | ||||
// for an item.. | // for an item.. | ||||
addSeparatorIfPending(); | |||||
items.add (new MenuItemInfo (itemResultId, | items.add (new MenuItemInfo (itemResultId, | ||||
String::empty, | String::empty, | ||||
true, | true, | ||||
@@ -1506,6 +1505,8 @@ void PopupMenu::addSubMenu (const String& subMenuName, | |||||
const bool isActive, | const bool isActive, | ||||
Image* const iconToUse) throw() | Image* const iconToUse) throw() | ||||
{ | { | ||||
addSeparatorIfPending(); | |||||
items.add (new MenuItemInfo (0, | items.add (new MenuItemInfo (0, | ||||
subMenuName, | subMenuName, | ||||
isActive && (subMenu.getNumItems() > 0), | isActive && (subMenu.getNumItems() > 0), | ||||
@@ -1520,7 +1521,7 @@ void PopupMenu::addSubMenu (const String& subMenuName, | |||||
void PopupMenu::addSeparator() throw() | void PopupMenu::addSeparator() throw() | ||||
{ | { | ||||
items.add (new MenuItemInfo()); | |||||
separatorPending = true; | |||||
} | } | ||||
@@ -381,6 +381,9 @@ private: | |||||
friend class MenuItemIterator; | friend class MenuItemIterator; | ||||
VoidArray items; | VoidArray items; | ||||
LookAndFeel* lookAndFeel; | LookAndFeel* lookAndFeel; | ||||
bool separatorPending; | |||||
void addSeparatorIfPending(); | |||||
int showMenu (const int x, const int y, const int w, const int h, | int showMenu (const int x, const int y, const int w, const int h, | ||||
const int itemIdThatMustBeVisible, | const int itemIdThatMustBeVisible, | ||||
@@ -137,6 +137,13 @@ public: | |||||
/** Returns the current play position of the movie. */ | /** Returns the current play position of the movie. */ | ||||
double getPosition() const; | double getPosition() const; | ||||
/** Changes the movie playback rate. | |||||
A value of 1 is normal speed, greater values play it proportionately faster, | |||||
smaller values play it slower. | |||||
*/ | |||||
void setSpeed (const float newSpeed); | |||||
/** Changes the movie's playback volume. | /** Changes the movie's playback volume. | ||||
@param newVolume the volume in the range 0 (silent) to 1.0 (full) | @param newVolume the volume in the range 0 (silent) to 1.0 (full) | ||||