@@ -200,7 +200,7 @@ public: | |||||
isRunning = false; | isRunning = false; | ||||
timeSliceThread.removeTimeSliceClient (this); | timeSliceThread.removeTimeSliceClient (this); | ||||
while (useTimeSlice() == 0) | |||||
while (writePendingData() == 0) | |||||
{} | {} | ||||
} | } | ||||
@@ -229,6 +229,11 @@ public: | |||||
} | } | ||||
int useTimeSlice() | int useTimeSlice() | ||||
{ | |||||
return writePendingData(); | |||||
} | |||||
int writePendingData() | |||||
{ | { | ||||
const int numToDo = getTotalSize() / 4; | const int numToDo = getTotalSize() / 4; | ||||
@@ -90,11 +90,6 @@ static const char* const oggExtensions[] = { ".ogg", 0 }; | |||||
//============================================================================== | //============================================================================== | ||||
class OggReader : public AudioFormatReader | class OggReader : public AudioFormatReader | ||||
{ | { | ||||
OggVorbisNamespace::OggVorbis_File ovFile; | |||||
OggVorbisNamespace::ov_callbacks callbacks; | |||||
AudioSampleBuffer reservoir; | |||||
int reservoirStart, samplesInReservoir; | |||||
public: | public: | ||||
//============================================================================== | //============================================================================== | ||||
OggReader (InputStream* const inp) | OggReader (InputStream* const inp) | ||||
@@ -242,33 +237,28 @@ public: | |||||
} | } | ||||
private: | private: | ||||
OggVorbisNamespace::OggVorbis_File ovFile; | |||||
OggVorbisNamespace::ov_callbacks callbacks; | |||||
AudioSampleBuffer reservoir; | |||||
int reservoirStart, samplesInReservoir; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OggReader); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OggReader); | ||||
}; | }; | ||||
//============================================================================== | //============================================================================== | ||||
class OggWriter : public AudioFormatWriter | class OggWriter : public AudioFormatWriter | ||||
{ | { | ||||
OggVorbisNamespace::ogg_stream_state os; | |||||
OggVorbisNamespace::ogg_page og; | |||||
OggVorbisNamespace::ogg_packet op; | |||||
OggVorbisNamespace::vorbis_info vi; | |||||
OggVorbisNamespace::vorbis_comment vc; | |||||
OggVorbisNamespace::vorbis_dsp_state vd; | |||||
OggVorbisNamespace::vorbis_block vb; | |||||
public: | public: | ||||
bool ok; | |||||
//============================================================================== | //============================================================================== | ||||
OggWriter (OutputStream* const out, | OggWriter (OutputStream* const out, | ||||
const double sampleRate, | const double sampleRate, | ||||
const int numChannels, | const int numChannels, | ||||
const int bitsPerSample, | const int bitsPerSample, | ||||
const int qualityIndex) | const int qualityIndex) | ||||
: AudioFormatWriter (out, TRANS (oggFormatName), sampleRate, numChannels, bitsPerSample) | |||||
: AudioFormatWriter (out, TRANS (oggFormatName), sampleRate, numChannels, bitsPerSample), | |||||
ok (false) | |||||
{ | { | ||||
using namespace OggVorbisNamespace; | using namespace OggVorbisNamespace; | ||||
ok = false; | |||||
vorbis_info_init (&vi); | vorbis_info_init (&vi); | ||||
@@ -314,7 +304,7 @@ public: | |||||
if (ok) | if (ok) | ||||
{ | { | ||||
// write a zero-length packet to show ogg that we're finished.. | // write a zero-length packet to show ogg that we're finished.. | ||||
write (0, 0); | |||||
writeSamples (0); | |||||
ogg_stream_clear (&os); | ogg_stream_clear (&os); | ||||
vorbis_block_clear (&vb); | vorbis_block_clear (&vb); | ||||
@@ -335,28 +325,38 @@ public: | |||||
//============================================================================== | //============================================================================== | ||||
bool write (const int** samplesToWrite, int numSamples) | bool write (const int** samplesToWrite, int numSamples) | ||||
{ | { | ||||
using namespace OggVorbisNamespace; | |||||
if (! ok) | |||||
return false; | |||||
if (numSamples > 0) | |||||
if (ok) | |||||
{ | { | ||||
const double gain = 1.0 / 0x80000000u; | |||||
float** const vorbisBuffer = vorbis_analysis_buffer (&vd, numSamples); | |||||
using namespace OggVorbisNamespace; | |||||
for (int i = numChannels; --i >= 0;) | |||||
if (numSamples > 0) | |||||
{ | { | ||||
float* const dst = vorbisBuffer[i]; | |||||
const int* const src = samplesToWrite [i]; | |||||
const double gain = 1.0 / 0x80000000u; | |||||
float** const vorbisBuffer = vorbis_analysis_buffer (&vd, numSamples); | |||||
if (src != nullptr && dst != nullptr) | |||||
for (int i = numChannels; --i >= 0;) | |||||
{ | { | ||||
for (int j = 0; j < numSamples; ++j) | |||||
dst[j] = (float) (src[j] * gain); | |||||
float* const dst = vorbisBuffer[i]; | |||||
const int* const src = samplesToWrite [i]; | |||||
if (src != nullptr && dst != nullptr) | |||||
{ | |||||
for (int j = 0; j < numSamples; ++j) | |||||
dst[j] = (float) (src[j] * gain); | |||||
} | |||||
} | } | ||||
} | } | ||||
writeSamples (numSamples); | |||||
} | } | ||||
return ok; | |||||
} | |||||
void writeSamples (int numSamples) | |||||
{ | |||||
using namespace OggVorbisNamespace; | |||||
vorbis_analysis_wrote (&vd, numSamples); | vorbis_analysis_wrote (&vd, numSamples); | ||||
while (vorbis_analysis_blockout (&vd, &vb) == 1) | while (vorbis_analysis_blockout (&vd, &vb) == 1) | ||||
@@ -381,11 +381,19 @@ public: | |||||
} | } | ||||
} | } | ||||
} | } | ||||
return true; | |||||
} | } | ||||
bool ok; | |||||
private: | private: | ||||
OggVorbisNamespace::ogg_stream_state os; | |||||
OggVorbisNamespace::ogg_page og; | |||||
OggVorbisNamespace::ogg_packet op; | |||||
OggVorbisNamespace::vorbis_info vi; | |||||
OggVorbisNamespace::vorbis_comment vc; | |||||
OggVorbisNamespace::vorbis_dsp_state vd; | |||||
OggVorbisNamespace::vorbis_block vb; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OggWriter); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OggWriter); | ||||
}; | }; | ||||
@@ -43,8 +43,6 @@ AudioFormatReaderSource::AudioFormatReaderSource (AudioFormatReader* const reade | |||||
AudioFormatReaderSource::~AudioFormatReaderSource() | AudioFormatReaderSource::~AudioFormatReaderSource() | ||||
{ | { | ||||
releaseResources(); | |||||
if (deleteReader) | if (deleteReader) | ||||
delete reader; | delete reader; | ||||
} | } | ||||
@@ -55,7 +55,7 @@ AudioTransportSource::~AudioTransportSource() | |||||
{ | { | ||||
setSource (nullptr); | setSource (nullptr); | ||||
releaseResources(); | |||||
releaseMasterResources(); | |||||
} | } | ||||
void AudioTransportSource::setSource (PositionableAudioSource* const newSource, | void AudioTransportSource::setSource (PositionableAudioSource* const newSource, | ||||
@@ -242,7 +242,7 @@ void AudioTransportSource::prepareToPlay (int samplesPerBlockExpected, | |||||
isPrepared = true; | isPrepared = true; | ||||
} | } | ||||
void AudioTransportSource::releaseResources() | |||||
void AudioTransportSource::releaseMasterResources() | |||||
{ | { | ||||
const ScopedLock sl (callbackLock); | const ScopedLock sl (callbackLock); | ||||
@@ -252,6 +252,11 @@ void AudioTransportSource::releaseResources() | |||||
isPrepared = false; | isPrepared = false; | ||||
} | } | ||||
void AudioTransportSource::releaseResources() | |||||
{ | |||||
releaseMasterResources(); | |||||
} | |||||
void AudioTransportSource::getNextAudioBlock (const AudioSourceChannelInfo& info) | void AudioTransportSource::getNextAudioBlock (const AudioSourceChannelInfo& info) | ||||
{ | { | ||||
const ScopedLock sl (callbackLock); | const ScopedLock sl (callbackLock); | ||||
@@ -176,6 +176,8 @@ private: | |||||
int blockSize, readAheadBufferSize; | int blockSize, readAheadBufferSize; | ||||
bool isPrepared, inputStreamEOF; | bool isPrepared, inputStreamEOF; | ||||
void releaseMasterResources(); | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioTransportSource); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioTransportSource); | ||||
}; | }; | ||||
@@ -301,8 +301,8 @@ int MidiMessage::getChannel() const noexcept | |||||
{ | { | ||||
if ((data[0] & 0xf0) != 0xf0) | if ((data[0] & 0xf0) != 0xf0) | ||||
return (data[0] & 0xf) + 1; | return (data[0] & 0xf) + 1; | ||||
else | |||||
return 0; | |||||
return 0; | |||||
} | } | ||||
bool MidiMessage::isForChannel (const int channel) const noexcept | bool MidiMessage::isForChannel (const int channel) const noexcept | ||||
@@ -355,8 +355,8 @@ uint8 MidiMessage::getVelocity() const noexcept | |||||
{ | { | ||||
if (isNoteOnOrOff()) | if (isNoteOnOrOff()) | ||||
return data[2]; | return data[2]; | ||||
else | |||||
return 0; | |||||
return 0; | |||||
} | } | ||||
float MidiMessage::getFloatVelocity() const noexcept | float MidiMessage::getFloatVelocity() const noexcept | ||||
@@ -383,6 +383,7 @@ bool MidiMessage::isAftertouch() const noexcept | |||||
int MidiMessage::getAfterTouchValue() const noexcept | int MidiMessage::getAfterTouchValue() const noexcept | ||||
{ | { | ||||
jassert (isAftertouch()); | |||||
return data[2]; | return data[2]; | ||||
} | } | ||||
@@ -407,7 +408,6 @@ bool MidiMessage::isChannelPressure() const noexcept | |||||
int MidiMessage::getChannelPressureValue() const noexcept | int MidiMessage::getChannelPressureValue() const noexcept | ||||
{ | { | ||||
jassert (isChannelPressure()); | jassert (isChannelPressure()); | ||||
return data[1]; | return data[1]; | ||||
} | } | ||||
@@ -427,6 +427,7 @@ bool MidiMessage::isProgramChange() const noexcept | |||||
int MidiMessage::getProgramChangeNumber() const noexcept | int MidiMessage::getProgramChangeNumber() const noexcept | ||||
{ | { | ||||
jassert (isProgramChange()); | |||||
return data[1]; | return data[1]; | ||||
} | } | ||||
@@ -445,6 +446,7 @@ bool MidiMessage::isPitchWheel() const noexcept | |||||
int MidiMessage::getPitchWheelValue() const noexcept | int MidiMessage::getPitchWheelValue() const noexcept | ||||
{ | { | ||||
jassert (isPitchWheel()); | |||||
return data[1] | (data[2] << 7); | return data[1] | (data[2] << 7); | ||||
} | } | ||||
@@ -454,7 +456,8 @@ const MidiMessage MidiMessage::pitchWheel (const int channel, | |||||
jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16 | jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16 | ||||
jassert (isPositiveAndBelow (position, (int) 0x4000)); | jassert (isPositiveAndBelow (position, (int) 0x4000)); | ||||
return MidiMessage (MidiHelpers::initialByte (0xe0, channel), position & 127, (position >> 7) & 127); | |||||
return MidiMessage (MidiHelpers::initialByte (0xe0, channel), | |||||
position & 127, (position >> 7) & 127); | |||||
} | } | ||||
bool MidiMessage::isController() const noexcept | bool MidiMessage::isController() const noexcept | ||||
@@ -465,14 +468,12 @@ bool MidiMessage::isController() const noexcept | |||||
int MidiMessage::getControllerNumber() const noexcept | int MidiMessage::getControllerNumber() const noexcept | ||||
{ | { | ||||
jassert (isController()); | jassert (isController()); | ||||
return data[1]; | return data[1]; | ||||
} | } | ||||
int MidiMessage::getControllerValue() const noexcept | int MidiMessage::getControllerValue() const noexcept | ||||
{ | { | ||||
jassert (isController()); | jassert (isController()); | ||||
return data[2]; | return data[2]; | ||||
} | } | ||||
@@ -481,12 +482,13 @@ const MidiMessage MidiMessage::controllerEvent (const int channel, const int con | |||||
// the channel must be between 1 and 16 inclusive | // the channel must be between 1 and 16 inclusive | ||||
jassert (channel > 0 && channel <= 16); | jassert (channel > 0 && channel <= 16); | ||||
return MidiMessage (MidiHelpers::initialByte (0xb0, channel), controllerType & 127, value & 127); | |||||
return MidiMessage (MidiHelpers::initialByte (0xb0, channel), | |||||
controllerType & 127, value & 127); | |||||
} | } | ||||
const MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const float velocity) noexcept | const MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const float velocity) noexcept | ||||
{ | { | ||||
return noteOn (channel, noteNumber, (uint8)(velocity * 127.0f)); | |||||
return noteOn (channel, noteNumber, (uint8) (velocity * 127.0f)); | |||||
} | } | ||||
const MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const uint8 velocity) noexcept | const MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const uint8 velocity) noexcept | ||||
@@ -494,7 +496,8 @@ const MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, | |||||
jassert (channel > 0 && channel <= 16); | jassert (channel > 0 && channel <= 16); | ||||
jassert (isPositiveAndBelow (noteNumber, (int) 128)); | jassert (isPositiveAndBelow (noteNumber, (int) 128)); | ||||
return MidiMessage (MidiHelpers::initialByte (0x90, channel), noteNumber & 127, MidiHelpers::validVelocity (velocity)); | |||||
return MidiMessage (MidiHelpers::initialByte (0x90, channel), | |||||
noteNumber & 127, MidiHelpers::validVelocity (velocity)); | |||||
} | } | ||||
const MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, uint8 velocity) noexcept | const MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, uint8 velocity) noexcept | ||||
@@ -502,7 +505,8 @@ const MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, | |||||
jassert (channel > 0 && channel <= 16); | jassert (channel > 0 && channel <= 16); | ||||
jassert (isPositiveAndBelow (noteNumber, (int) 128)); | jassert (isPositiveAndBelow (noteNumber, (int) 128)); | ||||
return MidiMessage (MidiHelpers::initialByte (0x80, channel), noteNumber & 127, MidiHelpers::validVelocity (velocity)); | |||||
return MidiMessage (MidiHelpers::initialByte (0x80, channel), | |||||
noteNumber & 127, MidiHelpers::validVelocity (velocity)); | |||||
} | } | ||||
const MidiMessage MidiMessage::allNotesOff (const int channel) noexcept | const MidiMessage MidiMessage::allNotesOff (const int channel) noexcept | ||||
@@ -534,15 +538,10 @@ const MidiMessage MidiMessage::masterVolume (const float volume) | |||||
{ | { | ||||
const int vol = jlimit (0, 0x3fff, roundToInt (volume * 0x4000)); | const int vol = jlimit (0, 0x3fff, roundToInt (volume * 0x4000)); | ||||
uint8 buf[8]; | |||||
buf[0] = 0xf0; | |||||
buf[1] = 0x7f; | |||||
buf[2] = 0x7f; | |||||
buf[3] = 0x04; | |||||
buf[4] = 0x01; | |||||
buf[5] = (uint8) (vol & 0x7f); | |||||
buf[6] = (uint8) (vol >> 7); | |||||
buf[7] = 0xf7; | |||||
const uint8 buf[] = { 0xf0, 0x7f, 0x7f, 0x04, 0x01, | |||||
(uint8) (vol & 0x7f), | |||||
(uint8) (vol >> 7), | |||||
0xf7 }; | |||||
return MidiMessage (buf, 8); | return MidiMessage (buf, 8); | ||||
} | } | ||||
@@ -574,17 +573,10 @@ int MidiMessage::getSysExDataSize() const noexcept | |||||
return isSysEx() ? size - 2 : 0; | return isSysEx() ? size - 2 : 0; | ||||
} | } | ||||
bool MidiMessage::isMetaEvent() const noexcept | |||||
{ | |||||
return *data == 0xff; | |||||
} | |||||
bool MidiMessage::isActiveSense() const noexcept | |||||
{ | |||||
return *data == 0xfe; | |||||
} | |||||
//============================================================================== | //============================================================================== | ||||
bool MidiMessage::isMetaEvent() const noexcept { return *data == 0xff; } | |||||
bool MidiMessage::isActiveSense() const noexcept { return *data == 0xfe; } | |||||
int MidiMessage::getMetaEventType() const noexcept | int MidiMessage::getMetaEventType() const noexcept | ||||
{ | { | ||||
return *data != 0xff ? -1 : data[1]; | return *data != 0xff ? -1 : data[1]; | ||||
@@ -603,26 +595,20 @@ int MidiMessage::getMetaEventLength() const noexcept | |||||
const uint8* MidiMessage::getMetaEventData() const noexcept | const uint8* MidiMessage::getMetaEventData() const noexcept | ||||
{ | { | ||||
jassert (isMetaEvent()); | |||||
int n; | int n; | ||||
const uint8* d = data + 2; | const uint8* d = data + 2; | ||||
readVariableLengthVal (d, n); | readVariableLengthVal (d, n); | ||||
return d + n; | return d + n; | ||||
} | } | ||||
bool MidiMessage::isTrackMetaEvent() const noexcept | |||||
{ | |||||
return getMetaEventType() == 0; | |||||
} | |||||
bool MidiMessage::isEndOfTrackMetaEvent() const noexcept | |||||
{ | |||||
return getMetaEventType() == 47; | |||||
} | |||||
bool MidiMessage::isTrackMetaEvent() const noexcept { return getMetaEventType() == 0; } | |||||
bool MidiMessage::isEndOfTrackMetaEvent() const noexcept { return getMetaEventType() == 47; } | |||||
bool MidiMessage::isTextMetaEvent() const noexcept | bool MidiMessage::isTextMetaEvent() const noexcept | ||||
{ | { | ||||
const int t = getMetaEventType(); | const int t = getMetaEventType(); | ||||
return t > 0 && t < 16; | return t > 0 && t < 16; | ||||
} | } | ||||
@@ -631,23 +617,13 @@ const String MidiMessage::getTextFromTextMetaEvent() const | |||||
return String (reinterpret_cast <const char*> (getMetaEventData()), getMetaEventLength()); | return String (reinterpret_cast <const char*> (getMetaEventData()), getMetaEventLength()); | ||||
} | } | ||||
bool MidiMessage::isTrackNameEvent() const noexcept | |||||
{ | |||||
return (data[1] == 3) && (*data == 0xff); | |||||
} | |||||
bool MidiMessage::isTempoMetaEvent() const noexcept | |||||
{ | |||||
return (data[1] == 81) && (*data == 0xff); | |||||
} | |||||
bool MidiMessage::isMidiChannelMetaEvent() const noexcept | |||||
{ | |||||
return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); | |||||
} | |||||
bool MidiMessage::isTrackNameEvent() const noexcept { return (data[1] == 3) && (*data == 0xff); } | |||||
bool MidiMessage::isTempoMetaEvent() const noexcept { return (data[1] == 81) && (*data == 0xff); } | |||||
bool MidiMessage::isMidiChannelMetaEvent() const noexcept { return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); } | |||||
int MidiMessage::getMidiChannelMetaEventChannel() const noexcept | int MidiMessage::getMidiChannelMetaEventChannel() const noexcept | ||||
{ | { | ||||
jassert (isMidiChannelMetaEvent()); | |||||
return data[3] + 1; | return data[3] + 1; | ||||
} | } | ||||
@@ -693,13 +669,10 @@ double MidiMessage::getTempoMetaEventTickLength (const short timeFormat) const n | |||||
const MidiMessage MidiMessage::tempoMetaEvent (int microsecondsPerQuarterNote) noexcept | const MidiMessage MidiMessage::tempoMetaEvent (int microsecondsPerQuarterNote) noexcept | ||||
{ | { | ||||
uint8 d[8]; | |||||
d[0] = 0xff; | |||||
d[1] = 81; | |||||
d[2] = 3; | |||||
d[3] = (uint8) (microsecondsPerQuarterNote >> 16); | |||||
d[4] = (uint8) ((microsecondsPerQuarterNote >> 8) & 0xff); | |||||
d[5] = (uint8) (microsecondsPerQuarterNote & 0xff); | |||||
const uint8 d[] = { 0xff, 81, 3, | |||||
(uint8) (microsecondsPerQuarterNote >> 16), | |||||
(uint8) (microsecondsPerQuarterNote >> 8), | |||||
(uint8) microsecondsPerQuarterNote }; | |||||
return MidiMessage (d, 6, 0.0); | return MidiMessage (d, 6, 0.0); | ||||
} | } | ||||
@@ -726,12 +699,6 @@ void MidiMessage::getTimeSignatureInfo (int& numerator, int& denominator) const | |||||
const MidiMessage MidiMessage::timeSignatureMetaEvent (const int numerator, const int denominator) | const MidiMessage MidiMessage::timeSignatureMetaEvent (const int numerator, const int denominator) | ||||
{ | { | ||||
uint8 d[8]; | |||||
d[0] = 0xff; | |||||
d[1] = 0x58; | |||||
d[2] = 0x04; | |||||
d[3] = (uint8) numerator; | |||||
int n = 1; | int n = 1; | ||||
int powerOfTwo = 0; | int powerOfTwo = 0; | ||||
@@ -741,20 +708,15 @@ const MidiMessage MidiMessage::timeSignatureMetaEvent (const int numerator, cons | |||||
++powerOfTwo; | ++powerOfTwo; | ||||
} | } | ||||
d[4] = (uint8) powerOfTwo; | |||||
d[5] = 0x01; | |||||
d[6] = 96; | |||||
const uint8 d[] = { 0xff, 0x58, 0x04, (uint8) numerator, | |||||
(uint8) powerOfTwo, 1, 96 }; | |||||
return MidiMessage (d, 7, 0.0); | return MidiMessage (d, 7, 0.0); | ||||
} | } | ||||
const MidiMessage MidiMessage::midiChannelMetaEvent (const int channel) noexcept | const MidiMessage MidiMessage::midiChannelMetaEvent (const int channel) noexcept | ||||
{ | { | ||||
uint8 d[8]; | |||||
d[0] = 0xff; | |||||
d[1] = 0x20; | |||||
d[2] = 0x01; | |||||
d[3] = (uint8) jlimit (0, 0xff, channel - 1); | |||||
const uint8 d[] = { 0xff, 0x20, 0x01, (uint8) jlimit (0, 0xff, channel - 1) }; | |||||
return MidiMessage (d, 4, 0.0); | return MidiMessage (d, 4, 0.0); | ||||
} | } | ||||
@@ -775,15 +737,8 @@ const MidiMessage MidiMessage::endOfTrack() noexcept | |||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
bool MidiMessage::isSongPositionPointer() const noexcept | |||||
{ | |||||
return *data == 0xf2; | |||||
} | |||||
int MidiMessage::getSongPositionPointerMidiBeat() const noexcept | |||||
{ | |||||
return data[1] | (data[2] << 7); | |||||
} | |||||
bool MidiMessage::isSongPositionPointer() const noexcept { return *data == 0xf2; } | |||||
int MidiMessage::getSongPositionPointerMidiBeat() const noexcept { return data[1] | (data[2] << 7); } | |||||
const MidiMessage MidiMessage::songPositionPointer (const int positionInMidiBeats) noexcept | const MidiMessage MidiMessage::songPositionPointer (const int positionInMidiBeats) noexcept | ||||
{ | { | ||||
@@ -792,63 +747,23 @@ const MidiMessage MidiMessage::songPositionPointer (const int positionInMidiBeat | |||||
(positionInMidiBeats >> 7) & 127); | (positionInMidiBeats >> 7) & 127); | ||||
} | } | ||||
bool MidiMessage::isMidiStart() const noexcept | |||||
{ | |||||
return *data == 0xfa; | |||||
} | |||||
bool MidiMessage::isMidiStart() const noexcept { return *data == 0xfa; } | |||||
const MidiMessage MidiMessage::midiStart() noexcept { return MidiMessage (0xfa); } | |||||
const MidiMessage MidiMessage::midiStart() noexcept | |||||
{ | |||||
return MidiMessage (0xfa); | |||||
} | |||||
bool MidiMessage::isMidiContinue() const noexcept { return *data == 0xfb; } | |||||
const MidiMessage MidiMessage::midiContinue() noexcept { return MidiMessage (0xfb); } | |||||
bool MidiMessage::isMidiContinue() const noexcept | |||||
{ | |||||
return *data == 0xfb; | |||||
} | |||||
const MidiMessage MidiMessage::midiContinue() noexcept | |||||
{ | |||||
return MidiMessage (0xfb); | |||||
} | |||||
bool MidiMessage::isMidiStop() const noexcept { return *data == 0xfc; } | |||||
const MidiMessage MidiMessage::midiStop() noexcept { return MidiMessage (0xfc); } | |||||
bool MidiMessage::isMidiStop() const noexcept | |||||
{ | |||||
return *data == 0xfc; | |||||
} | |||||
bool MidiMessage::isMidiClock() const noexcept { return *data == 0xf8; } | |||||
const MidiMessage MidiMessage::midiClock() noexcept { return MidiMessage (0xf8); } | |||||
const MidiMessage MidiMessage::midiStop() noexcept | |||||
{ | |||||
return MidiMessage (0xfc); | |||||
} | |||||
bool MidiMessage::isQuarterFrame() const noexcept { return *data == 0xf1; } | |||||
int MidiMessage::getQuarterFrameSequenceNumber() const noexcept { return ((int) data[1]) >> 4; } | |||||
int MidiMessage::getQuarterFrameValue() const noexcept { return ((int) data[1]) & 0x0f; } | |||||
bool MidiMessage::isMidiClock() const noexcept | |||||
{ | |||||
return *data == 0xf8; | |||||
} | |||||
const MidiMessage MidiMessage::midiClock() noexcept | |||||
{ | |||||
return MidiMessage (0xf8); | |||||
} | |||||
bool MidiMessage::isQuarterFrame() const noexcept | |||||
{ | |||||
return *data == 0xf1; | |||||
} | |||||
int MidiMessage::getQuarterFrameSequenceNumber() const noexcept | |||||
{ | |||||
return ((int) data[1]) >> 4; | |||||
} | |||||
int MidiMessage::getQuarterFrameValue() const noexcept | |||||
{ | |||||
return ((int) data[1]) & 0x0f; | |||||
} | |||||
const MidiMessage MidiMessage::quarterFrame (const int sequenceNumber, | |||||
const int value) noexcept | |||||
const MidiMessage MidiMessage::quarterFrame (const int sequenceNumber, const int value) noexcept | |||||
{ | { | ||||
return MidiMessage (0xf1, (sequenceNumber << 4) | value); | return MidiMessage (0xf1, (sequenceNumber << 4) | value); | ||||
} | } | ||||
@@ -862,10 +777,7 @@ bool MidiMessage::isFullFrame() const noexcept | |||||
&& data[4] == 0x01; | && data[4] == 0x01; | ||||
} | } | ||||
void MidiMessage::getFullFrameParameters (int& hours, | |||||
int& minutes, | |||||
int& seconds, | |||||
int& frames, | |||||
void MidiMessage::getFullFrameParameters (int& hours, int& minutes, int& seconds, int& frames, | |||||
MidiMessage::SmpteTimecodeType& timecodeType) const noexcept | MidiMessage::SmpteTimecodeType& timecodeType) const noexcept | ||||
{ | { | ||||
jassert (isFullFrame()); | jassert (isFullFrame()); | ||||
@@ -877,23 +789,16 @@ void MidiMessage::getFullFrameParameters (int& hours, | |||||
frames = data[8]; | frames = data[8]; | ||||
} | } | ||||
const MidiMessage MidiMessage::fullFrame (const int hours, | |||||
const int minutes, | |||||
const int seconds, | |||||
const int frames, | |||||
const MidiMessage MidiMessage::fullFrame (const int hours, const int minutes, | |||||
const int seconds, const int frames, | |||||
MidiMessage::SmpteTimecodeType timecodeType) | MidiMessage::SmpteTimecodeType timecodeType) | ||||
{ | { | ||||
uint8 d[10]; | |||||
d[0] = 0xf0; | |||||
d[1] = 0x7f; | |||||
d[2] = 0x7f; | |||||
d[3] = 0x01; | |||||
d[4] = 0x01; | |||||
d[5] = (uint8) ((hours & 0x01f) | (timecodeType << 5)); | |||||
d[6] = (uint8) minutes; | |||||
d[7] = (uint8) seconds; | |||||
d[8] = (uint8) frames; | |||||
d[9] = 0xf7; | |||||
const uint8 d[] = { 0xf0, 0x7f, 0x7f, 0x01, 0x01, | |||||
(uint8) ((hours & 0x01f) | (timecodeType << 5)), | |||||
(uint8) minutes, | |||||
(uint8) seconds, | |||||
(uint8) frames, | |||||
0xf7 }; | |||||
return MidiMessage (d, 10, 0.0); | return MidiMessage (d, 10, 0.0); | ||||
} | } | ||||
@@ -915,22 +820,13 @@ MidiMessage::MidiMachineControlCommand MidiMessage::getMidiMachineControlCommand | |||||
const MidiMessage MidiMessage::midiMachineControlCommand (MidiMessage::MidiMachineControlCommand command) | const MidiMessage MidiMessage::midiMachineControlCommand (MidiMessage::MidiMachineControlCommand command) | ||||
{ | { | ||||
uint8 d[6]; | |||||
d[0] = 0xf0; | |||||
d[1] = 0x7f; | |||||
d[2] = 0x00; | |||||
d[3] = 0x06; | |||||
d[4] = (uint8) command; | |||||
d[5] = 0xf7; | |||||
const uint8 d[] = { 0xf0, 0x7f, 0, 6, (uint8) command, 0xf7 }; | |||||
return MidiMessage (d, 6, 0.0); | return MidiMessage (d, 6, 0.0); | ||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
bool MidiMessage::isMidiMachineControlGoto (int& hours, | |||||
int& minutes, | |||||
int& seconds, | |||||
int& frames) const noexcept | |||||
bool MidiMessage::isMidiMachineControlGoto (int& hours, int& minutes, int& seconds, int& frames) const noexcept | |||||
{ | { | ||||
if (size >= 12 | if (size >= 12 | ||||
&& data[0] == 0xf0 | && data[0] == 0xf0 | ||||
@@ -951,24 +847,14 @@ bool MidiMessage::isMidiMachineControlGoto (int& hours, | |||||
return false; | return false; | ||||
} | } | ||||
const MidiMessage MidiMessage::midiMachineControlGoto (int hours, | |||||
int minutes, | |||||
int seconds, | |||||
int frames) | |||||
{ | |||||
uint8 d[12]; | |||||
d[0] = 0xf0; | |||||
d[1] = 0x7f; | |||||
d[2] = 0x00; | |||||
d[3] = 0x06; | |||||
d[4] = 0x44; | |||||
d[5] = 0x06; | |||||
d[6] = 0x01; | |||||
d[7] = (uint8) hours; | |||||
d[8] = (uint8) minutes; | |||||
d[9] = (uint8) seconds; | |||||
d[10] = (uint8) frames; | |||||
d[11] = 0xf7; | |||||
const MidiMessage MidiMessage::midiMachineControlGoto (int hours, int minutes, int seconds, int frames) | |||||
{ | |||||
const uint8 d[] = { 0xf0, 0x7f, 0, 6, 0x44, 6, 1, | |||||
(uint8) hours, | |||||
(uint8) minutes, | |||||
(uint8) seconds, | |||||
(uint8) frames, | |||||
0xf7 }; | |||||
return MidiMessage (d, 12, 0.0); | return MidiMessage (d, 12, 0.0); | ||||
} | } | ||||
@@ -55,7 +55,7 @@ PluginListComponent::PluginListComponent (KnownPluginList& listToEdit, | |||||
setSize (400, 600); | setSize (400, 600); | ||||
list.addChangeListener (this); | list.addChangeListener (this); | ||||
changeListenerCallback (nullptr); | |||||
updateList(); | |||||
} | } | ||||
PluginListComponent::~PluginListComponent() | PluginListComponent::~PluginListComponent() | ||||
@@ -71,6 +71,11 @@ void PluginListComponent::resized() | |||||
} | } | ||||
void PluginListComponent::changeListenerCallback (ChangeBroadcaster*) | void PluginListComponent::changeListenerCallback (ChangeBroadcaster*) | ||||
{ | |||||
updateList(); | |||||
} | |||||
void PluginListComponent::updateList() | |||||
{ | { | ||||
listBox.updateContent(); | listBox.updateContent(); | ||||
listBox.repaint(); | listBox.repaint(); | ||||
@@ -92,6 +92,7 @@ private: | |||||
void scanFor (AudioPluginFormat* format); | void scanFor (AudioPluginFormat* format); | ||||
static void optionsMenuStaticCallback (int result, PluginListComponent*); | static void optionsMenuStaticCallback (int result, PluginListComponent*); | ||||
void optionsMenuCallback (int result); | void optionsMenuCallback (int result); | ||||
void updateList(); | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginListComponent); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginListComponent); | ||||
}; | }; | ||||
@@ -378,16 +378,16 @@ void var::swapWith (var& other) noexcept | |||||
std::swap (value, other.value); | std::swap (value, other.value); | ||||
} | } | ||||
var& var::operator= (const var& newValue) { type->cleanUp (value); type = newValue.type; type->createCopy (value, newValue.value); return *this; } | |||||
var& var::operator= (const int newValue) { type->cleanUp (value); type = &VariantType_Int::instance; value.intValue = newValue; return *this; } | |||||
var& var::operator= (const int64 newValue) { type->cleanUp (value); type = &VariantType_Int64::instance; value.int64Value = newValue; return *this; } | |||||
var& var::operator= (const bool newValue) { type->cleanUp (value); type = &VariantType_Bool::instance; value.boolValue = newValue; return *this; } | |||||
var& var::operator= (const double newValue) { type->cleanUp (value); type = &VariantType_Double::instance; value.doubleValue = newValue; return *this; } | |||||
var& var::operator= (const char* const newValue) { var v (newValue); swapWith (v); return *this; } | |||||
var& var::operator= (const wchar_t* const newValue) { var v (newValue); swapWith (v); return *this; } | |||||
var& var::operator= (const String& newValue) { var v (newValue); swapWith (v); return *this; } | |||||
var& var::operator= (ReferenceCountedObject* newValue) { var v (newValue); swapWith (v); return *this; } | |||||
var& var::operator= (MethodFunction newValue) { var v (newValue); swapWith (v); return *this; } | |||||
const var& var::operator= (const var& newValue) { type->cleanUp (value); type = newValue.type; type->createCopy (value, newValue.value); return *this; } | |||||
const var& var::operator= (const int newValue) { type->cleanUp (value); type = &VariantType_Int::instance; value.intValue = newValue; return *this; } | |||||
const var& var::operator= (const int64 newValue) { type->cleanUp (value); type = &VariantType_Int64::instance; value.int64Value = newValue; return *this; } | |||||
const var& var::operator= (const bool newValue) { type->cleanUp (value); type = &VariantType_Bool::instance; value.boolValue = newValue; return *this; } | |||||
const var& var::operator= (const double newValue) { type->cleanUp (value); type = &VariantType_Double::instance; value.doubleValue = newValue; return *this; } | |||||
const var& var::operator= (const char* const newValue) { var v (newValue); swapWith (v); return *this; } | |||||
const var& var::operator= (const wchar_t* const newValue) { var v (newValue); swapWith (v); return *this; } | |||||
const var& var::operator= (const String& newValue) { var v (newValue); swapWith (v); return *this; } | |||||
const var& var::operator= (ReferenceCountedObject* newValue) { var v (newValue); swapWith (v); return *this; } | |||||
const var& var::operator= (MethodFunction newValue) { var v (newValue); swapWith (v); return *this; } | |||||
//============================================================================== | //============================================================================== | ||||
bool var::equals (const var& other) const noexcept | bool var::equals (const var& other) const noexcept | ||||
@@ -73,16 +73,16 @@ public: | |||||
var (ReferenceCountedObject* object); | var (ReferenceCountedObject* object); | ||||
var (MethodFunction method) noexcept; | var (MethodFunction method) noexcept; | ||||
var& operator= (const var& valueToCopy); | |||||
var& operator= (int value); | |||||
var& operator= (int64 value); | |||||
var& operator= (bool value); | |||||
var& operator= (double value); | |||||
var& operator= (const char* value); | |||||
var& operator= (const wchar_t* value); | |||||
var& operator= (const String& value); | |||||
var& operator= (ReferenceCountedObject* object); | |||||
var& operator= (MethodFunction method); | |||||
const var& operator= (const var& valueToCopy); | |||||
const var& operator= (int value); | |||||
const var& operator= (int64 value); | |||||
const var& operator= (bool value); | |||||
const var& operator= (double value); | |||||
const var& operator= (const char* value); | |||||
const var& operator= (const wchar_t* value); | |||||
const var& operator= (const String& value); | |||||
const var& operator= (ReferenceCountedObject* object); | |||||
const var& operator= (MethodFunction method); | |||||
void swapWith (var& other) noexcept; | void swapWith (var& other) noexcept; | ||||
@@ -55,7 +55,7 @@ FileLogger::FileLogger (const File& logFile_, | |||||
<< welcomeMessage << newLine | << welcomeMessage << newLine | ||||
<< "Log started: " << Time::getCurrentTime().toString (true, true) << newLine; | << "Log started: " << Time::getCurrentTime().toString (true, true) << newLine; | ||||
logMessage (welcome); | |||||
FileLogger::logMessage (welcome); | |||||
} | } | ||||
FileLogger::~FileLogger() | FileLogger::~FileLogger() | ||||
@@ -45,7 +45,7 @@ ArrowButton::ArrowButton (const String& name, | |||||
0.5f, 0.5f)); | 0.5f, 0.5f)); | ||||
setComponentEffect (&shadow); | setComponentEffect (&shadow); | ||||
buttonStateChanged(); | |||||
updateShadowAndOffset(); | |||||
} | } | ||||
ArrowButton::~ArrowButton() | ArrowButton::~ArrowButton() | ||||
@@ -66,6 +66,11 @@ void ArrowButton::paintButton (Graphics& g, | |||||
} | } | ||||
void ArrowButton::buttonStateChanged() | void ArrowButton::buttonStateChanged() | ||||
{ | |||||
updateShadowAndOffset(); | |||||
} | |||||
void ArrowButton::updateShadowAndOffset() | |||||
{ | { | ||||
offset = (isDown()) ? 1 : 0; | offset = (isDown()) ? 1 : 0; | ||||
@@ -72,6 +72,8 @@ private: | |||||
Path path; | Path path; | ||||
int offset; | int offset; | ||||
void updateShadowAndOffset(); | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ArrowButton); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ArrowButton); | ||||
}; | }; | ||||
@@ -59,7 +59,7 @@ ComboBox::ComboBox (const String& name) | |||||
noChoicesMessage (TRANS("(no choices)")) | noChoicesMessage (TRANS("(no choices)")) | ||||
{ | { | ||||
setRepaintsOnMouseActivity (true); | setRepaintsOnMouseActivity (true); | ||||
lookAndFeelChanged(); | |||||
ComboBox::lookAndFeelChanged(); | |||||
currentId.addListener (this); | currentId.addListener (this); | ||||
} | } | ||||
@@ -355,8 +355,8 @@ ListBox::ListBox (const String& name, ListBoxModel* const model_) | |||||
{ | { | ||||
addAndMakeVisible (viewport = new ListViewport (*this)); | addAndMakeVisible (viewport = new ListViewport (*this)); | ||||
setWantsKeyboardFocus (true); | |||||
colourChanged(); | |||||
ListBox::setWantsKeyboardFocus (true); | |||||
ListBox::colourChanged(); | |||||
} | } | ||||
ListBox::~ListBox() | ListBox::~ListBox() | ||||
@@ -52,8 +52,7 @@ public: | |||||
void paintContent (Graphics& g, int w, int h) | void paintContent (Graphics& g, int w, int h) | ||||
{ | { | ||||
g.setFont (font); | g.setFont (font); | ||||
g.setColour (Colours::black); | |||||
g.setColour (findColour (TooltipWindow::textColourId, true)); | |||||
g.drawFittedText (text, 0, 0, w, h, Justification::centred, 1); | g.drawFittedText (text, 0, 0, w, h, Justification::centred, 1); | ||||
} | } | ||||
@@ -130,7 +129,7 @@ Slider::Slider (const String& name) | |||||
setWantsKeyboardFocus (false); | setWantsKeyboardFocus (false); | ||||
setRepaintsOnMouseActivity (true); | setRepaintsOnMouseActivity (true); | ||||
lookAndFeelChanged(); | |||||
Slider::lookAndFeelChanged(); | |||||
updateText(); | updateText(); | ||||
currentValue.addListener (this); | currentValue.addListener (this); | ||||
@@ -1029,8 +1028,7 @@ void Slider::mouseDown (const MouseEvent& e) | |||||
{ | { | ||||
mouseWasHidden = false; | mouseWasHidden = false; | ||||
incDecDragged = false; | incDecDragged = false; | ||||
mouseXWhenLastDragged = e.x; | |||||
mouseYWhenLastDragged = e.y; | |||||
mousePosWhenLastDragged = e.getPosition(); | |||||
mouseDragStartX = e.getMouseDownX(); | mouseDragStartX = e.getMouseDownX(); | ||||
mouseDragStartY = e.getMouseDownY(); | mouseDragStartY = e.getMouseDownY(); | ||||
@@ -1223,8 +1221,8 @@ void Slider::mouseDrag (const MouseEvent& e) | |||||
{ | { | ||||
if (style == Rotary) | if (style == Rotary) | ||||
{ | { | ||||
int dx = e.x - sliderRect.getCentreX(); | |||||
int dy = e.y - sliderRect.getCentreY(); | |||||
const int dx = e.x - sliderRect.getCentreX(); | |||||
const int dy = e.y - sliderRect.getCentreY(); | |||||
if (dx * dx + dy * dy > 25) | if (dx * dx + dy * dy > 25) | ||||
{ | { | ||||
@@ -1329,8 +1327,8 @@ void Slider::mouseDrag (const MouseEvent& e) | |||||
{ | { | ||||
const int mouseDiff = (isHorizontal() || style == RotaryHorizontalDrag | const int mouseDiff = (isHorizontal() || style == RotaryHorizontalDrag | ||||
|| (style == IncDecButtons && incDecDragDirectionIsHorizontal())) | || (style == IncDecButtons && incDecDragDirectionIsHorizontal())) | ||||
? e.x - mouseXWhenLastDragged | |||||
: e.y - mouseYWhenLastDragged; | |||||
? e.x - mousePosWhenLastDragged.getX() | |||||
: e.y - mousePosWhenLastDragged.getY(); | |||||
const double maxSpeed = jmax (200, sliderRegionSize); | const double maxSpeed = jmax (200, sliderRegionSize); | ||||
double speed = jlimit (0.0, maxSpeed, (double) abs (mouseDiff)); | double speed = jlimit (0.0, maxSpeed, (double) abs (mouseDiff)); | ||||
@@ -1389,8 +1387,7 @@ void Slider::mouseDrag (const MouseEvent& e) | |||||
minMaxDiff = (double) valueMax.getValue() - (double) valueMin.getValue(); | minMaxDiff = (double) valueMax.getValue() - (double) valueMin.getValue(); | ||||
} | } | ||||
mouseXWhenLastDragged = e.x; | |||||
mouseYWhenLastDragged = e.y; | |||||
mousePosWhenLastDragged = e.getPosition(); | |||||
} | } | ||||
} | } | ||||
@@ -825,7 +825,8 @@ private: | |||||
double velocityModeSensitivity, velocityModeOffset, minMaxDiff; | double velocityModeSensitivity, velocityModeOffset, minMaxDiff; | ||||
int velocityModeThreshold; | int velocityModeThreshold; | ||||
float rotaryStart, rotaryEnd; | float rotaryStart, rotaryEnd; | ||||
int numDecimalPlaces, mouseXWhenLastDragged, mouseYWhenLastDragged; | |||||
int numDecimalPlaces; | |||||
Point<int> mousePosWhenLastDragged; | |||||
int mouseDragStartX, mouseDragStartY; | int mouseDragStartX, mouseDragStartY; | ||||
int sliderRegionStart, sliderRegionSize; | int sliderRegionStart, sliderRegionSize; | ||||
int sliderBeingDragged; | int sliderBeingDragged; | ||||
@@ -101,19 +101,7 @@ FileBrowserComponent::FileBrowserComponent (int flags_, | |||||
addAndMakeVisible (¤tPathBox); | addAndMakeVisible (¤tPathBox); | ||||
currentPathBox.setEditableText (true); | currentPathBox.setEditableText (true); | ||||
StringArray rootNames, rootPaths; | |||||
getRoots (rootNames, rootPaths); | |||||
for (int i = 0; i < rootNames.size(); ++i) | |||||
{ | |||||
if (rootNames[i].isEmpty()) | |||||
currentPathBox.addSeparator(); | |||||
else | |||||
currentPathBox.addItem (rootNames[i], i + 1); | |||||
} | |||||
currentPathBox.addSeparator(); | |||||
resetRecentPaths(); | |||||
currentPathBox.addListener (this); | currentPathBox.addListener (this); | ||||
addAndMakeVisible (&filenameBox); | addAndMakeVisible (&filenameBox); | ||||
@@ -271,6 +259,24 @@ void FileBrowserComponent::setRoot (const File& newRootDirectory) | |||||
&& currentRoot.getParentDirectory() != currentRoot); | && currentRoot.getParentDirectory() != currentRoot); | ||||
} | } | ||||
void FileBrowserComponent::resetRecentPaths() | |||||
{ | |||||
currentPathBox.clear(); | |||||
StringArray rootNames, rootPaths; | |||||
getRoots (rootNames, rootPaths); | |||||
for (int i = 0; i < rootNames.size(); ++i) | |||||
{ | |||||
if (rootNames[i].isEmpty()) | |||||
currentPathBox.addSeparator(); | |||||
else | |||||
currentPathBox.addItem (rootNames[i], i + 1); | |||||
} | |||||
currentPathBox.addSeparator(); | |||||
} | |||||
void FileBrowserComponent::goUp() | void FileBrowserComponent::goUp() | ||||
{ | { | ||||
setRoot (getRoot().getParentDirectory()); | setRoot (getRoot().getParentDirectory()); | ||||
@@ -475,7 +481,7 @@ void FileBrowserComponent::comboBoxChanged (ComboBox*) | |||||
void FileBrowserComponent::getRoots (StringArray& rootNames, StringArray& rootPaths) | void FileBrowserComponent::getRoots (StringArray& rootNames, StringArray& rootPaths) | ||||
{ | { | ||||
#if JUCE_WINDOWS | |||||
#if JUCE_WINDOWS | |||||
Array<File> roots; | Array<File> roots; | ||||
File::findFileSystemRoots (roots); | File::findFileSystemRoots (roots); | ||||
rootPaths.clear(); | rootPaths.clear(); | ||||
@@ -511,9 +517,8 @@ void FileBrowserComponent::getRoots (StringArray& rootNames, StringArray& rootPa | |||||
rootNames.add ("Documents"); | rootNames.add ("Documents"); | ||||
rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName()); | rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName()); | ||||
rootNames.add ("Desktop"); | rootNames.add ("Desktop"); | ||||
#endif | |||||
#if JUCE_MAC | |||||
#elif JUCE_MAC | |||||
rootPaths.add (File::getSpecialLocation (File::userHomeDirectory).getFullPathName()); | rootPaths.add (File::getSpecialLocation (File::userHomeDirectory).getFullPathName()); | ||||
rootNames.add ("Home folder"); | rootNames.add ("Home folder"); | ||||
rootPaths.add (File::getSpecialLocation (File::userDocumentsDirectory).getFullPathName()); | rootPaths.add (File::getSpecialLocation (File::userDocumentsDirectory).getFullPathName()); | ||||
@@ -538,16 +543,15 @@ void FileBrowserComponent::getRoots (StringArray& rootNames, StringArray& rootPa | |||||
rootNames.add (volume.getFileName()); | rootNames.add (volume.getFileName()); | ||||
} | } | ||||
} | } | ||||
#endif | |||||
#if JUCE_LINUX | |||||
#else | |||||
rootPaths.add ("/"); | rootPaths.add ("/"); | ||||
rootNames.add ("/"); | rootNames.add ("/"); | ||||
rootPaths.add (File::getSpecialLocation (File::userHomeDirectory).getFullPathName()); | rootPaths.add (File::getSpecialLocation (File::userHomeDirectory).getFullPathName()); | ||||
rootNames.add ("Home folder"); | rootNames.add ("Home folder"); | ||||
rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName()); | rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName()); | ||||
rootNames.add ("Desktop"); | rootNames.add ("Desktop"); | ||||
#endif | |||||
#endif | |||||
} | } | ||||
@@ -212,6 +212,9 @@ protected: | |||||
*/ | */ | ||||
virtual void getRoots (StringArray& rootNames, StringArray& rootPaths); | virtual void getRoots (StringArray& rootNames, StringArray& rootPaths); | ||||
/** Updates the items in the dropdown list of recent paths with the values from getRoots(). */ | |||||
void resetRecentPaths(); | |||||
private: | private: | ||||
//============================================================================== | //============================================================================== | ||||
ScopedPointer <DirectoryContentsList> fileList; | ScopedPointer <DirectoryContentsList> fileList; | ||||
@@ -117,7 +117,7 @@ FileChooserDialogBox::FileChooserDialogBox (const String& name, | |||||
content->newFolderButton.addListener (this); | content->newFolderButton.addListener (this); | ||||
content->chooserComponent.addListener (this); | content->chooserComponent.addListener (this); | ||||
selectionChanged(); | |||||
FileChooserDialogBox::selectionChanged(); | |||||
} | } | ||||
FileChooserDialogBox::~FileChooserDialogBox() | FileChooserDialogBox::~FileChooserDialogBox() | ||||
@@ -127,7 +127,55 @@ namespace KeyPressHelpers | |||||
{ "rewind", KeyPress::rewindKey } | { "rewind", KeyPress::rewindKey } | ||||
}; | }; | ||||
const String numberPadPrefix() { return "numpad "; } | |||||
struct ModifierDescription | |||||
{ | |||||
const char* name; | |||||
int flag; | |||||
}; | |||||
static const ModifierDescription modifierNames[] = | |||||
{ | |||||
{ "ctrl", ModifierKeys::ctrlModifier }, | |||||
{ "control", ModifierKeys::ctrlModifier }, | |||||
{ "ctl", ModifierKeys::ctrlModifier }, | |||||
{ "shift", ModifierKeys::shiftModifier }, | |||||
{ "shft", ModifierKeys::shiftModifier }, | |||||
{ "alt", ModifierKeys::altModifier }, | |||||
{ "option", ModifierKeys::altModifier }, | |||||
{ "command", ModifierKeys::commandModifier }, | |||||
{ "cmd", ModifierKeys::commandModifier } | |||||
}; | |||||
const char* numberPadPrefix() noexcept { return "numpad "; } | |||||
int getNumpadKeyCode (const String& desc) | |||||
{ | |||||
if (desc.containsIgnoreCase (numberPadPrefix())) | |||||
{ | |||||
const juce_wchar lastChar = desc.trimEnd().getLastCharacter(); | |||||
switch (lastChar) | |||||
{ | |||||
case '0': case '1': case '2': case '3': case '4': | |||||
case '5': case '6': case '7': case '8': case '9': | |||||
return KeyPress::numberPad0 + lastChar - '0'; | |||||
case '+': return KeyPress::numberPadAdd; | |||||
case '-': return KeyPress::numberPadSubtract; | |||||
case '*': return KeyPress::numberPadMultiply; | |||||
case '/': return KeyPress::numberPadDivide; | |||||
case '.': return KeyPress::numberPadDecimalPoint; | |||||
case '=': return KeyPress::numberPadEquals; | |||||
default: break; | |||||
} | |||||
if (desc.endsWith ("separator")) return KeyPress::numberPadSeparator; | |||||
if (desc.endsWith ("delete")) return KeyPress::numberPadDelete; | |||||
} | |||||
return 0; | |||||
} | |||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
@@ -135,22 +183,9 @@ const KeyPress KeyPress::createFromDescription (const String& desc) | |||||
{ | { | ||||
int modifiers = 0; | int modifiers = 0; | ||||
if (desc.containsWholeWordIgnoreCase ("ctrl") | |||||
|| desc.containsWholeWordIgnoreCase ("control") | |||||
|| desc.containsWholeWordIgnoreCase ("ctl")) | |||||
modifiers |= ModifierKeys::ctrlModifier; | |||||
if (desc.containsWholeWordIgnoreCase ("shift") | |||||
|| desc.containsWholeWordIgnoreCase ("shft")) | |||||
modifiers |= ModifierKeys::shiftModifier; | |||||
if (desc.containsWholeWordIgnoreCase ("alt") | |||||
|| desc.containsWholeWordIgnoreCase ("option")) | |||||
modifiers |= ModifierKeys::altModifier; | |||||
if (desc.containsWholeWordIgnoreCase ("command") | |||||
|| desc.containsWholeWordIgnoreCase ("cmd")) | |||||
modifiers |= ModifierKeys::commandModifier; | |||||
for (int i = 0; i < numElementsInArray (KeyPressHelpers::modifierNames); ++i) | |||||
if (desc.containsWholeWordIgnoreCase (KeyPressHelpers::modifierNames[i].name)) | |||||
modifiers |= KeyPressHelpers::modifierNames[i].flag; | |||||
int key = 0; | int key = 0; | ||||
@@ -164,44 +199,28 @@ const KeyPress KeyPress::createFromDescription (const String& desc) | |||||
} | } | ||||
if (key == 0) | if (key == 0) | ||||
{ | |||||
// see if it's a numpad key.. | |||||
if (desc.containsIgnoreCase (KeyPressHelpers::numberPadPrefix())) | |||||
{ | |||||
const juce_wchar lastChar = desc.trimEnd().getLastCharacter(); | |||||
key = KeyPressHelpers::getNumpadKeyCode (desc); | |||||
if (lastChar >= '0' && lastChar <= '9') key = numberPad0 + lastChar - '0'; | |||||
else if (lastChar == '+') key = numberPadAdd; | |||||
else if (lastChar == '-') key = numberPadSubtract; | |||||
else if (lastChar == '*') key = numberPadMultiply; | |||||
else if (lastChar == '/') key = numberPadDivide; | |||||
else if (lastChar == '.') key = numberPadDecimalPoint; | |||||
else if (lastChar == '=') key = numberPadEquals; | |||||
else if (desc.endsWith ("separator")) key = numberPadSeparator; | |||||
else if (desc.endsWith ("delete")) key = numberPadDelete; | |||||
} | |||||
if (key == 0) | |||||
{ | |||||
// see if it's a function key.. | |||||
if (! desc.containsChar ('#')) // avoid mistaking hex-codes like "#f1" | |||||
for (int i = 1; i <= 12; ++i) | |||||
if (desc.containsWholeWordIgnoreCase ("f" + String (i))) | |||||
key = F1Key + i - 1; | |||||
if (key == 0) | if (key == 0) | ||||
{ | { | ||||
// see if it's a function key.. | |||||
if (! desc.containsChar ('#')) // avoid mistaking hex-codes like "#f1" | |||||
for (int i = 1; i <= 12; ++i) | |||||
if (desc.containsWholeWordIgnoreCase ("f" + String (i))) | |||||
key = F1Key + i - 1; | |||||
if (key == 0) | |||||
{ | |||||
// give up and use the hex code.. | |||||
const int hexCode = desc.fromFirstOccurrenceOf ("#", false, false) | |||||
.toLowerCase() | |||||
.retainCharacters ("0123456789abcdef") | |||||
.getHexValue32(); | |||||
if (hexCode > 0) | |||||
key = hexCode; | |||||
else | |||||
key = CharacterFunctions::toUpperCase (desc.getLastCharacter()); | |||||
} | |||||
// give up and use the hex code.. | |||||
const int hexCode = desc.fromFirstOccurrenceOf ("#", false, false) | |||||
.toLowerCase() | |||||
.retainCharacters ("0123456789abcdef") | |||||
.getHexValue32(); | |||||
if (hexCode > 0) | |||||
key = hexCode; | |||||
else | |||||
key = CharacterFunctions::toUpperCase (desc.getLastCharacter()); | |||||
} | } | ||||
} | } | ||||
@@ -100,10 +100,6 @@ public: | |||||
setOutlineThickness (1); | setOutlineThickness (1); | ||||
} | } | ||||
~MidiInputSelectorComponentListBox() | |||||
{ | |||||
} | |||||
int getNumRows() | int getNumRows() | ||||
{ | { | ||||
return items.size(); | return items.size(); | ||||
@@ -223,7 +219,7 @@ public: | |||||
type->scanForDevices(); | type->scanForDevices(); | ||||
setup.manager->addChangeListener (this); | setup.manager->addChangeListener (this); | ||||
changeListenerCallback (nullptr); | |||||
updateAllControls(); | |||||
} | } | ||||
~AudioDeviceSettingsPanel() | ~AudioDeviceSettingsPanel() | ||||
@@ -398,71 +394,15 @@ public: | |||||
} | } | ||||
} | } | ||||
void updateControlPanelButton() | |||||
void updateAllControls() | |||||
{ | { | ||||
AudioIODevice* const currentDevice = setup.manager->getCurrentAudioDevice(); | |||||
showUIButton = nullptr; | |||||
updateOutputsComboBox(); | |||||
updateInputsComboBox(); | |||||
if (currentDevice != nullptr && currentDevice->hasControlPanel()) | |||||
{ | |||||
addAndMakeVisible (showUIButton = new TextButton (TRANS ("show this device's control panel"), | |||||
TRANS ("opens the device's own control panel"))); | |||||
showUIButton->addListener (this); | |||||
} | |||||
resized(); | |||||
} | |||||
updateControlPanelButton(); | |||||
void changeListenerCallback (ChangeBroadcaster*) | |||||
{ | |||||
AudioIODevice* const currentDevice = setup.manager->getCurrentAudioDevice(); | AudioIODevice* const currentDevice = setup.manager->getCurrentAudioDevice(); | ||||
if (setup.maxNumOutputChannels > 0 || ! type->hasSeparateInputsAndOutputs()) | |||||
{ | |||||
if (outputDeviceDropDown == nullptr) | |||||
{ | |||||
outputDeviceDropDown = new ComboBox (String::empty); | |||||
outputDeviceDropDown->addListener (this); | |||||
addAndMakeVisible (outputDeviceDropDown); | |||||
outputDeviceLabel = new Label (String::empty, | |||||
type->hasSeparateInputsAndOutputs() ? TRANS ("output:") | |||||
: TRANS ("device:")); | |||||
outputDeviceLabel->attachToComponent (outputDeviceDropDown, true); | |||||
if (setup.maxNumOutputChannels > 0) | |||||
{ | |||||
addAndMakeVisible (testButton = new TextButton (TRANS ("Test"))); | |||||
testButton->addListener (this); | |||||
} | |||||
} | |||||
addNamesToDeviceBox (*outputDeviceDropDown, false); | |||||
} | |||||
if (setup.maxNumInputChannels > 0 && type->hasSeparateInputsAndOutputs()) | |||||
{ | |||||
if (inputDeviceDropDown == nullptr) | |||||
{ | |||||
inputDeviceDropDown = new ComboBox (String::empty); | |||||
inputDeviceDropDown->addListener (this); | |||||
addAndMakeVisible (inputDeviceDropDown); | |||||
inputDeviceLabel = new Label (String::empty, TRANS ("input:")); | |||||
inputDeviceLabel->attachToComponent (inputDeviceDropDown, true); | |||||
addAndMakeVisible (inputLevelMeter | |||||
= new SimpleDeviceManagerInputLevelMeter (setup.manager)); | |||||
} | |||||
addNamesToDeviceBox (*inputDeviceDropDown, true); | |||||
} | |||||
updateControlPanelButton(); | |||||
showCorrectDeviceName (inputDeviceDropDown, true); | |||||
showCorrectDeviceName (outputDeviceDropDown, false); | |||||
if (currentDevice != nullptr) | if (currentDevice != nullptr) | ||||
{ | { | ||||
if (setup.maxNumOutputChannels > 0 | if (setup.maxNumOutputChannels > 0 | ||||
@@ -505,66 +445,8 @@ public: | |||||
inputChanList = nullptr; | inputChanList = nullptr; | ||||
} | } | ||||
// sample rate.. | |||||
{ | |||||
if (sampleRateDropDown == nullptr) | |||||
{ | |||||
addAndMakeVisible (sampleRateDropDown = new ComboBox (String::empty)); | |||||
sampleRateLabel = new Label (String::empty, TRANS ("sample rate:")); | |||||
sampleRateLabel->attachToComponent (sampleRateDropDown, true); | |||||
} | |||||
else | |||||
{ | |||||
sampleRateDropDown->clear(); | |||||
sampleRateDropDown->removeListener (this); | |||||
} | |||||
const int numRates = currentDevice->getNumSampleRates(); | |||||
for (int i = 0; i < numRates; ++i) | |||||
{ | |||||
const int rate = roundToInt (currentDevice->getSampleRate (i)); | |||||
sampleRateDropDown->addItem (String (rate) + " Hz", rate); | |||||
} | |||||
sampleRateDropDown->setSelectedId (roundToInt (currentDevice->getCurrentSampleRate()), true); | |||||
sampleRateDropDown->addListener (this); | |||||
} | |||||
// buffer size | |||||
{ | |||||
if (bufferSizeDropDown == nullptr) | |||||
{ | |||||
addAndMakeVisible (bufferSizeDropDown = new ComboBox (String::empty)); | |||||
bufferSizeLabel = new Label (String::empty, TRANS ("audio buffer size:")); | |||||
bufferSizeLabel->attachToComponent (bufferSizeDropDown, true); | |||||
} | |||||
else | |||||
{ | |||||
bufferSizeDropDown->clear(); | |||||
bufferSizeDropDown->removeListener (this); | |||||
} | |||||
const int numBufferSizes = currentDevice->getNumBufferSizesAvailable(); | |||||
double currentRate = currentDevice->getCurrentSampleRate(); | |||||
if (currentRate == 0) | |||||
currentRate = 48000.0; | |||||
for (int i = 0; i < numBufferSizes; ++i) | |||||
{ | |||||
const int bs = currentDevice->getBufferSizeSamples (i); | |||||
bufferSizeDropDown->addItem (String (bs) | |||||
+ " samples (" | |||||
+ String (bs * 1000.0 / currentRate, 1) | |||||
+ " ms)", | |||||
bs); | |||||
} | |||||
bufferSizeDropDown->setSelectedId (currentDevice->getCurrentBufferSizeSamples(), true); | |||||
bufferSizeDropDown->addListener (this); | |||||
} | |||||
updateSampleRateComboBox (currentDevice); | |||||
updateBufferSizeComboBox (currentDevice); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -586,6 +468,11 @@ public: | |||||
setSize (getWidth(), getLowestY() + 4); | setSize (getWidth(), getLowestY() + 4); | ||||
} | } | ||||
void changeListenerCallback (ChangeBroadcaster*) | |||||
{ | |||||
updateAllControls(); | |||||
} | |||||
private: | private: | ||||
AudioIODeviceType* const type; | AudioIODeviceType* const type; | ||||
const AudioIODeviceType::DeviceSetupDetails setup; | const AudioIODeviceType::DeviceSetupDetails setup; | ||||
@@ -634,6 +521,133 @@ private: | |||||
return y; | return y; | ||||
} | } | ||||
void updateControlPanelButton() | |||||
{ | |||||
AudioIODevice* const currentDevice = setup.manager->getCurrentAudioDevice(); | |||||
showUIButton = nullptr; | |||||
if (currentDevice != nullptr && currentDevice->hasControlPanel()) | |||||
{ | |||||
addAndMakeVisible (showUIButton = new TextButton (TRANS ("show this device's control panel"), | |||||
TRANS ("opens the device's own control panel"))); | |||||
showUIButton->addListener (this); | |||||
} | |||||
resized(); | |||||
} | |||||
void updateOutputsComboBox() | |||||
{ | |||||
if (setup.maxNumOutputChannels > 0 || ! type->hasSeparateInputsAndOutputs()) | |||||
{ | |||||
if (outputDeviceDropDown == nullptr) | |||||
{ | |||||
outputDeviceDropDown = new ComboBox (String::empty); | |||||
outputDeviceDropDown->addListener (this); | |||||
addAndMakeVisible (outputDeviceDropDown); | |||||
outputDeviceLabel = new Label (String::empty, | |||||
type->hasSeparateInputsAndOutputs() ? TRANS ("output:") | |||||
: TRANS ("device:")); | |||||
outputDeviceLabel->attachToComponent (outputDeviceDropDown, true); | |||||
if (setup.maxNumOutputChannels > 0) | |||||
{ | |||||
addAndMakeVisible (testButton = new TextButton (TRANS ("Test"))); | |||||
testButton->addListener (this); | |||||
} | |||||
} | |||||
addNamesToDeviceBox (*outputDeviceDropDown, false); | |||||
} | |||||
showCorrectDeviceName (outputDeviceDropDown, false); | |||||
} | |||||
void updateInputsComboBox() | |||||
{ | |||||
if (setup.maxNumInputChannels > 0 && type->hasSeparateInputsAndOutputs()) | |||||
{ | |||||
if (inputDeviceDropDown == nullptr) | |||||
{ | |||||
inputDeviceDropDown = new ComboBox (String::empty); | |||||
inputDeviceDropDown->addListener (this); | |||||
addAndMakeVisible (inputDeviceDropDown); | |||||
inputDeviceLabel = new Label (String::empty, TRANS ("input:")); | |||||
inputDeviceLabel->attachToComponent (inputDeviceDropDown, true); | |||||
addAndMakeVisible (inputLevelMeter | |||||
= new SimpleDeviceManagerInputLevelMeter (setup.manager)); | |||||
} | |||||
addNamesToDeviceBox (*inputDeviceDropDown, true); | |||||
} | |||||
showCorrectDeviceName (inputDeviceDropDown, true); | |||||
} | |||||
void updateSampleRateComboBox (AudioIODevice* currentDevice) | |||||
{ | |||||
if (sampleRateDropDown == nullptr) | |||||
{ | |||||
addAndMakeVisible (sampleRateDropDown = new ComboBox (String::empty)); | |||||
sampleRateLabel = new Label (String::empty, TRANS ("sample rate:")); | |||||
sampleRateLabel->attachToComponent (sampleRateDropDown, true); | |||||
} | |||||
else | |||||
{ | |||||
sampleRateDropDown->clear(); | |||||
sampleRateDropDown->removeListener (this); | |||||
} | |||||
const int numRates = currentDevice->getNumSampleRates(); | |||||
for (int i = 0; i < numRates; ++i) | |||||
{ | |||||
const int rate = roundToInt (currentDevice->getSampleRate (i)); | |||||
sampleRateDropDown->addItem (String (rate) + " Hz", rate); | |||||
} | |||||
sampleRateDropDown->setSelectedId (roundToInt (currentDevice->getCurrentSampleRate()), true); | |||||
sampleRateDropDown->addListener (this); | |||||
} | |||||
void updateBufferSizeComboBox (AudioIODevice* currentDevice) | |||||
{ | |||||
if (bufferSizeDropDown == nullptr) | |||||
{ | |||||
addAndMakeVisible (bufferSizeDropDown = new ComboBox (String::empty)); | |||||
bufferSizeLabel = new Label (String::empty, TRANS ("audio buffer size:")); | |||||
bufferSizeLabel->attachToComponent (bufferSizeDropDown, true); | |||||
} | |||||
else | |||||
{ | |||||
bufferSizeDropDown->clear(); | |||||
bufferSizeDropDown->removeListener (this); | |||||
} | |||||
const int numBufferSizes = currentDevice->getNumBufferSizesAvailable(); | |||||
double currentRate = currentDevice->getCurrentSampleRate(); | |||||
if (currentRate == 0) | |||||
currentRate = 48000.0; | |||||
for (int i = 0; i < numBufferSizes; ++i) | |||||
{ | |||||
const int bs = currentDevice->getBufferSizeSamples (i); | |||||
bufferSizeDropDown->addItem (String (bs) | |||||
+ " samples (" | |||||
+ String (bs * 1000.0 / currentRate, 1) | |||||
+ " ms)", | |||||
bs); | |||||
} | |||||
bufferSizeDropDown->setSelectedId (currentDevice->getCurrentBufferSizeSamples(), true); | |||||
bufferSizeDropDown->addListener (this); | |||||
} | |||||
public: | public: | ||||
//============================================================================== | //============================================================================== | ||||
class ChannelSelectorListBox : public ListBox, | class ChannelSelectorListBox : public ListBox, | ||||
@@ -660,10 +674,6 @@ public: | |||||
setOutlineThickness (1); | setOutlineThickness (1); | ||||
} | } | ||||
~ChannelSelectorListBox() | |||||
{ | |||||
} | |||||
void refresh() | void refresh() | ||||
{ | { | ||||
items.clear(); | items.clear(); | ||||
@@ -712,10 +722,7 @@ public: | |||||
return items.size(); | return items.size(); | ||||
} | } | ||||
void paintListBoxItem (int row, | |||||
Graphics& g, | |||||
int width, int height, | |||||
bool rowIsSelected) | |||||
void paintListBoxItem (int row, Graphics& g, int width, int height, bool rowIsSelected) | |||||
{ | { | ||||
if (isPositiveAndBelow (row, items.size())) | if (isPositiveAndBelow (row, items.size())) | ||||
{ | { | ||||
@@ -969,7 +976,7 @@ AudioDeviceSelectorComponent::AudioDeviceSelectorComponent (AudioDeviceManager& | |||||
} | } | ||||
deviceManager_.addChangeListener (this); | deviceManager_.addChangeListener (this); | ||||
changeListenerCallback (nullptr); | |||||
updateAllControls(); | |||||
} | } | ||||
AudioDeviceSelectorComponent::~AudioDeviceSelectorComponent() | AudioDeviceSelectorComponent::~AudioDeviceSelectorComponent() | ||||
@@ -1040,7 +1047,7 @@ void AudioDeviceSelectorComponent::comboBoxChanged (ComboBox* comboBoxThatHasCha | |||||
deviceManager.setCurrentAudioDeviceType (type->getTypeName(), true); | deviceManager.setCurrentAudioDeviceType (type->getTypeName(), true); | ||||
changeListenerCallback (nullptr); // needed in case the type hasn't actally changed | |||||
updateAllControls(); // needed in case the type hasn't actally changed | |||||
} | } | ||||
} | } | ||||
else if (comboBoxThatHasChanged == midiOutputSelector) | else if (comboBoxThatHasChanged == midiOutputSelector) | ||||
@@ -1050,11 +1057,14 @@ void AudioDeviceSelectorComponent::comboBoxChanged (ComboBox* comboBoxThatHasCha | |||||
} | } | ||||
void AudioDeviceSelectorComponent::changeListenerCallback (ChangeBroadcaster*) | void AudioDeviceSelectorComponent::changeListenerCallback (ChangeBroadcaster*) | ||||
{ | |||||
updateAllControls(); | |||||
} | |||||
void AudioDeviceSelectorComponent::updateAllControls() | |||||
{ | { | ||||
if (deviceTypeDropDown != nullptr) | if (deviceTypeDropDown != nullptr) | ||||
{ | |||||
deviceTypeDropDown->setText (deviceManager.getCurrentAudioDeviceType(), false); | deviceTypeDropDown->setText (deviceManager.getCurrentAudioDeviceType(), false); | ||||
} | |||||
if (audioDeviceSettingsComp == nullptr | if (audioDeviceSettingsComp == nullptr | ||||
|| audioDeviceSettingsCompType != deviceManager.getCurrentAudioDeviceType()) | || audioDeviceSettingsCompType != deviceManager.getCurrentAudioDeviceType()) | ||||
@@ -107,6 +107,8 @@ private: | |||||
ScopedPointer<ComboBox> midiOutputSelector; | ScopedPointer<ComboBox> midiOutputSelector; | ||||
ScopedPointer<Label> midiInputsLabel, midiOutputLabel; | ScopedPointer<Label> midiInputsLabel, midiOutputLabel; | ||||
void updateAllControls(); | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioDeviceSelectorComponent); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioDeviceSelectorComponent); | ||||
}; | }; | ||||
@@ -102,7 +102,7 @@ AlertWindow::AlertWindow (const String& title, | |||||
if (! JUCEApplication::isStandaloneApp()) | if (! JUCEApplication::isStandaloneApp()) | ||||
setAlwaysOnTop (true); // for a plugin, make it always-on-top because the host windows are often top-level | setAlwaysOnTop (true); // for a plugin, make it always-on-top because the host windows are often top-level | ||||
lookAndFeelChanged(); | |||||
AlertWindow::lookAndFeelChanged(); | |||||
constrainer.setMinimumOnscreenAmounts (0x10000, 0x10000, 0x10000, 0x10000); | constrainer.setMinimumOnscreenAmounts (0x10000, 0x10000, 0x10000, 0x10000); | ||||
} | } | ||||
@@ -78,7 +78,7 @@ DocumentWindow::DocumentWindow (const String& title, | |||||
{ | { | ||||
setResizeLimits (128, 128, 32768, 32768); | setResizeLimits (128, 128, 32768, 32768); | ||||
lookAndFeelChanged(); | |||||
DocumentWindow::lookAndFeelChanged(); | |||||
} | } | ||||
DocumentWindow::~DocumentWindow() | DocumentWindow::~DocumentWindow() | ||||
@@ -41,18 +41,12 @@ ResizableWindow::ResizableWindow (const String& name, | |||||
ownsContentComponent (false), | ownsContentComponent (false), | ||||
resizeToFitContent (false), | resizeToFitContent (false), | ||||
fullscreen (false), | fullscreen (false), | ||||
lastNonFullScreenPos (50, 50, 256, 256), | |||||
constrainer (nullptr) | constrainer (nullptr) | ||||
#if JUCE_DEBUG | #if JUCE_DEBUG | ||||
, hasBeenResized (false) | , hasBeenResized (false) | ||||
#endif | #endif | ||||
{ | { | ||||
defaultConstrainer.setMinimumOnscreenAmounts (0x10000, 16, 24, 16); | |||||
lastNonFullScreenPos.setBounds (50, 50, 256, 256); | |||||
if (addToDesktop_) | |||||
Component::addToDesktop (getDesktopWindowStyleFlags()); | |||||
initialise (addToDesktop_); | |||||
} | } | ||||
ResizableWindow::ResizableWindow (const String& name, | ResizableWindow::ResizableWindow (const String& name, | ||||
@@ -62,7 +56,6 @@ ResizableWindow::ResizableWindow (const String& name, | |||||
ownsContentComponent (false), | ownsContentComponent (false), | ||||
resizeToFitContent (false), | resizeToFitContent (false), | ||||
fullscreen (false), | fullscreen (false), | ||||
lastNonFullScreenPos (50, 50, 256, 256), | |||||
constrainer (nullptr) | constrainer (nullptr) | ||||
#if JUCE_DEBUG | #if JUCE_DEBUG | ||||
, hasBeenResized (false) | , hasBeenResized (false) | ||||
@@ -70,10 +63,7 @@ ResizableWindow::ResizableWindow (const String& name, | |||||
{ | { | ||||
setBackgroundColour (backgroundColour_); | setBackgroundColour (backgroundColour_); | ||||
defaultConstrainer.setMinimumOnscreenAmounts (0x10000, 16, 24, 16); | |||||
if (addToDesktop_) | |||||
Component::addToDesktop (getDesktopWindowStyleFlags()); | |||||
initialise (addToDesktop_); | |||||
} | } | ||||
ResizableWindow::~ResizableWindow() | ResizableWindow::~ResizableWindow() | ||||
@@ -93,6 +83,16 @@ ResizableWindow::~ResizableWindow() | |||||
jassert (getNumChildComponents() == 0); | jassert (getNumChildComponents() == 0); | ||||
} | } | ||||
void ResizableWindow::initialise (const bool addToDesktop) | |||||
{ | |||||
defaultConstrainer.setMinimumOnscreenAmounts (0x10000, 16, 24, 16); | |||||
lastNonFullScreenPos.setBounds (50, 50, 256, 256); | |||||
if (addToDesktop) | |||||
Component::addToDesktop (ResizableWindow::getDesktopWindowStyleFlags()); | |||||
} | |||||
int ResizableWindow::getDesktopWindowStyleFlags() const | int ResizableWindow::getDesktopWindowStyleFlags() const | ||||
{ | { | ||||
int styleFlags = TopLevelWindow::getDesktopWindowStyleFlags(); | int styleFlags = TopLevelWindow::getDesktopWindowStyleFlags(); | ||||
@@ -372,6 +372,7 @@ private: | |||||
bool hasBeenResized; | bool hasBeenResized; | ||||
#endif | #endif | ||||
void initialise (bool addToDesktop); | |||||
void updateLastPos(); | void updateLastPos(); | ||||
void setContent (Component* newComp, bool takeOwnership, bool resizeToFit); | void setContent (Component* newComp, bool takeOwnership, bool resizeToFit); | ||||
@@ -149,7 +149,7 @@ TopLevelWindow::TopLevelWindow (const String& name, | |||||
setOpaque (true); | setOpaque (true); | ||||
if (addToDesktop_) | if (addToDesktop_) | ||||
Component::addToDesktop (getDesktopWindowStyleFlags()); | |||||
Component::addToDesktop (TopLevelWindow::getDesktopWindowStyleFlags()); | |||||
else | else | ||||
setDropShadowEnabled (true); | setDropShadowEnabled (true); | ||||
@@ -43,22 +43,17 @@ class GIFLoader | |||||
public: | public: | ||||
GIFLoader (InputStream& in) | GIFLoader (InputStream& in) | ||||
: input (in), | : input (in), | ||||
dataBlockIsZero (false), | |||||
fresh (false), | |||||
finished (false) | |||||
dataBlockIsZero (false), fresh (false), finished (false), | |||||
currentBit (0), lastBit (0), lastByteIndex (0), | |||||
codeSize (0), setCodeSize (0), | |||||
maxCode (0), maxCodeSize (0), | |||||
firstcode (0), oldcode (0), clearCode (0), endCode (0) | |||||
{ | { | ||||
currentBit = lastBit = lastByteIndex = 0; | |||||
maxCode = maxCodeSize = codeSize = setCodeSize = 0; | |||||
firstcode = oldcode = 0; | |||||
clearCode = end_code = 0; | |||||
int imageWidth, imageHeight; | int imageWidth, imageHeight; | ||||
int transparent = -1; | int transparent = -1; | ||||
if (! getSizeFromHeader (imageWidth, imageHeight)) | |||||
return; | |||||
if ((imageWidth <= 0) || (imageHeight <= 0)) | |||||
if (! (getSizeFromHeader (imageWidth, imageHeight) | |||||
&& imageWidth > 0 && imageHeight > 0)) | |||||
return; | return; | ||||
unsigned char buf [16]; | unsigned char buf [16]; | ||||
@@ -112,8 +107,6 @@ public: | |||||
} | } | ||||
} | } | ||||
~GIFLoader() {} | |||||
Image image; | Image image; | ||||
private: | private: | ||||
@@ -125,11 +118,11 @@ private: | |||||
int codeSize, setCodeSize; | int codeSize, setCodeSize; | ||||
int maxCode, maxCodeSize; | int maxCode, maxCodeSize; | ||||
int firstcode, oldcode; | int firstcode, oldcode; | ||||
int clearCode, end_code; | |||||
int clearCode, endCode; | |||||
enum { maxGifCode = 1 << 12 }; | enum { maxGifCode = 1 << 12 }; | ||||
int table [2] [maxGifCode]; | int table [2] [maxGifCode]; | ||||
int stack [2 * maxGifCode]; | int stack [2 * maxGifCode]; | ||||
int *sp; | |||||
int* sp; | |||||
bool getSizeFromHeader (int& w, int& h) | bool getSizeFromHeader (int& w, int& h) | ||||
{ | { | ||||
@@ -208,40 +201,41 @@ private: | |||||
return n; | return n; | ||||
} | } | ||||
int readLZWByte (const bool initialise, const int inputCodeSize) | |||||
void clearTable() | |||||
{ | { | ||||
int code, incode, i; | |||||
if (initialise) | |||||
int i; | |||||
for (i = 0; i < clearCode; ++i) | |||||
{ | { | ||||
setCodeSize = inputCodeSize; | |||||
codeSize = setCodeSize + 1; | |||||
clearCode = 1 << setCodeSize; | |||||
end_code = clearCode + 1; | |||||
maxCodeSize = 2 * clearCode; | |||||
maxCode = clearCode + 2; | |||||
getCode (0, true); | |||||
fresh = true; | |||||
for (i = 0; i < clearCode; ++i) | |||||
{ | |||||
table[0][i] = 0; | |||||
table[1][i] = i; | |||||
} | |||||
table[0][i] = 0; | |||||
table[1][i] = i; | |||||
} | |||||
for (; i < maxGifCode; ++i) | |||||
{ | |||||
table[0][i] = 0; | |||||
table[1][i] = 0; | |||||
} | |||||
for (; i < maxGifCode; ++i) | |||||
{ | |||||
table[0][i] = 0; | |||||
table[1][i] = 0; | |||||
} | |||||
} | |||||
sp = stack; | |||||
void initialise (const int inputCodeSize) | |||||
{ | |||||
setCodeSize = inputCodeSize; | |||||
codeSize = setCodeSize + 1; | |||||
clearCode = 1 << setCodeSize; | |||||
endCode = clearCode + 1; | |||||
maxCodeSize = 2 * clearCode; | |||||
maxCode = clearCode + 2; | |||||
getCode (0, true); | |||||
fresh = true; | |||||
clearTable(); | |||||
sp = stack; | |||||
} | |||||
return 0; | |||||
} | |||||
else if (fresh) | |||||
int readLZWByte (const int inputCodeSize) | |||||
{ | |||||
if (fresh) | |||||
{ | { | ||||
fresh = false; | fresh = false; | ||||
@@ -258,31 +252,21 @@ private: | |||||
if (sp > stack) | if (sp > stack) | ||||
return *--sp; | return *--sp; | ||||
int code; | |||||
while ((code = getCode (codeSize, false)) >= 0) | while ((code = getCode (codeSize, false)) >= 0) | ||||
{ | { | ||||
if (code == clearCode) | if (code == clearCode) | ||||
{ | { | ||||
for (i = 0; i < clearCode; ++i) | |||||
{ | |||||
table[0][i] = 0; | |||||
table[1][i] = i; | |||||
} | |||||
for (; i < maxGifCode; ++i) | |||||
{ | |||||
table[0][i] = 0; | |||||
table[1][i] = 0; | |||||
} | |||||
clearTable(); | |||||
codeSize = setCodeSize + 1; | codeSize = setCodeSize + 1; | ||||
maxCodeSize = 2 * clearCode; | maxCodeSize = 2 * clearCode; | ||||
maxCode = clearCode + 2; | maxCode = clearCode + 2; | ||||
sp = stack; | sp = stack; | ||||
firstcode = oldcode = getCode (codeSize, false); | firstcode = oldcode = getCode (codeSize, false); | ||||
return firstcode; | return firstcode; | ||||
} | } | ||||
else if (code == end_code) | |||||
else if (code == endCode) | |||||
{ | { | ||||
if (dataBlockIsZero) | if (dataBlockIsZero) | ||||
return -2; | return -2; | ||||
@@ -297,7 +281,7 @@ private: | |||||
return -2; | return -2; | ||||
} | } | ||||
incode = code; | |||||
const int incode = code; | |||||
if (code >= maxCode) | if (code >= maxCode) | ||||
{ | { | ||||
@@ -385,10 +369,11 @@ private: | |||||
{ | { | ||||
unsigned char c; | unsigned char c; | ||||
if (input.read (&c, 1) != 1 | |||||
|| readLZWByte (true, c) < 0) | |||||
if (input.read (&c, 1) != 1) | |||||
return false; | return false; | ||||
initialise (c); | |||||
if (transparent >= 0) | if (transparent >= 0) | ||||
{ | { | ||||
palette [transparent][0] = 0; | palette [transparent][0] = 0; | ||||
@@ -404,7 +389,7 @@ private: | |||||
uint8* p = destData.data; | uint8* p = destData.data; | ||||
const bool hasAlpha = image.hasAlphaChannel(); | const bool hasAlpha = image.hasAlphaChannel(); | ||||
while ((index = readLZWByte (false, c)) >= 0) | |||||
while ((index = readLZWByte (c)) >= 0) | |||||
{ | { | ||||
const uint8* const paletteEntry = palette [index]; | const uint8* const paletteEntry = palette [index]; | ||||
@@ -47,7 +47,8 @@ FileOutputStream::FileOutputStream (const File& f, const int bufferSize_) | |||||
FileOutputStream::~FileOutputStream() | FileOutputStream::~FileOutputStream() | ||||
{ | { | ||||
flush(); | |||||
flushBuffer(); | |||||
flushInternal(); | |||||
closeHandle(); | closeHandle(); | ||||
} | } | ||||
@@ -60,21 +61,29 @@ bool FileOutputStream::setPosition (int64 newPosition) | |||||
{ | { | ||||
if (newPosition != currentPosition) | if (newPosition != currentPosition) | ||||
{ | { | ||||
flush(); | |||||
flushBuffer(); | |||||
currentPosition = juce_fileSetPosition (fileHandle, newPosition); | currentPosition = juce_fileSetPosition (fileHandle, newPosition); | ||||
} | } | ||||
return newPosition == currentPosition; | return newPosition == currentPosition; | ||||
} | } | ||||
void FileOutputStream::flush() | |||||
bool FileOutputStream::flushBuffer() | |||||
{ | { | ||||
bool ok = true; | |||||
if (bytesInBuffer > 0) | if (bytesInBuffer > 0) | ||||
{ | { | ||||
writeInternal (buffer, bytesInBuffer); | |||||
ok = writeInternal (buffer, bytesInBuffer); | |||||
bytesInBuffer = 0; | bytesInBuffer = 0; | ||||
} | } | ||||
return ok; | |||||
} | |||||
void FileOutputStream::flush() | |||||
{ | |||||
flushBuffer(); | |||||
flushInternal(); | flushInternal(); | ||||
} | } | ||||
@@ -88,15 +97,8 @@ bool FileOutputStream::write (const void* const src, const int numBytes) | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
if (bytesInBuffer > 0) | |||||
{ | |||||
// flush the reservoir | |||||
const bool wroteOk = (writeInternal (buffer, bytesInBuffer) == bytesInBuffer); | |||||
bytesInBuffer = 0; | |||||
if (! wroteOk) | |||||
return false; | |||||
} | |||||
if (! flushBuffer()) | |||||
return false; | |||||
if (numBytes < bufferSize) | if (numBytes < bufferSize) | ||||
{ | { | ||||
@@ -97,6 +97,7 @@ private: | |||||
void openHandle(); | void openHandle(); | ||||
void closeHandle(); | void closeHandle(); | ||||
void flushInternal(); | void flushInternal(); | ||||
bool flushBuffer(); | |||||
int64 setPositionInternal (int64 newPosition); | int64 setPositionInternal (int64 newPosition); | ||||
int writeInternal (const void* data, int numBytes); | int writeInternal (const void* data, int numBytes); | ||||
@@ -143,11 +143,11 @@ GZIPCompressorOutputStream::GZIPCompressorOutputStream (OutputStream* const dest | |||||
GZIPCompressorOutputStream::~GZIPCompressorOutputStream() | GZIPCompressorOutputStream::~GZIPCompressorOutputStream() | ||||
{ | { | ||||
flush(); | |||||
flushInternal(); | |||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
void GZIPCompressorOutputStream::flush() | |||||
void GZIPCompressorOutputStream::flushInternal() | |||||
{ | { | ||||
if (! helper->finished) | if (! helper->finished) | ||||
{ | { | ||||
@@ -160,6 +160,11 @@ void GZIPCompressorOutputStream::flush() | |||||
destStream->flush(); | destStream->flush(); | ||||
} | } | ||||
void GZIPCompressorOutputStream::flush() | |||||
{ | |||||
flushInternal(); | |||||
} | |||||
bool GZIPCompressorOutputStream::write (const void* destBuffer, int howMany) | bool GZIPCompressorOutputStream::write (const void* destBuffer, int howMany) | ||||
{ | { | ||||
if (! helper->finished) | if (! helper->finished) | ||||
@@ -85,6 +85,7 @@ private: | |||||
friend class ScopedPointer <GZIPCompressorHelper>; | friend class ScopedPointer <GZIPCompressorHelper>; | ||||
ScopedPointer <GZIPCompressorHelper> helper; | ScopedPointer <GZIPCompressorHelper> helper; | ||||
bool doNextBlock(); | bool doNextBlock(); | ||||
void flushInternal(); | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GZIPCompressorOutputStream); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GZIPCompressorOutputStream); | ||||
}; | }; | ||||
@@ -51,10 +51,15 @@ MemoryOutputStream::MemoryOutputStream (MemoryBlock& memoryBlockToWriteTo, | |||||
MemoryOutputStream::~MemoryOutputStream() | MemoryOutputStream::~MemoryOutputStream() | ||||
{ | { | ||||
flush(); | |||||
trimExternalBlockSize(); | |||||
} | } | ||||
void MemoryOutputStream::flush() | void MemoryOutputStream::flush() | ||||
{ | |||||
trimExternalBlockSize(); | |||||
} | |||||
void MemoryOutputStream::trimExternalBlockSize() | |||||
{ | { | ||||
if (&data != &internalBlock) | if (&data != &internalBlock) | ||||
data.setSize (size, false); | data.setSize (size, false); | ||||
@@ -116,6 +116,8 @@ private: | |||||
MemoryBlock internalBlock; | MemoryBlock internalBlock; | ||||
size_t position, size; | size_t position, size; | ||||
void trimExternalBlockSize(); | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryOutputStream); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryOutputStream); | ||||
}; | }; | ||||
@@ -39,7 +39,7 @@ SubregionStream::SubregionStream (InputStream* const sourceStream, | |||||
startPositionInSourceStream (startPositionInSourceStream_), | startPositionInSourceStream (startPositionInSourceStream_), | ||||
lengthOfSourceStream (lengthOfSourceStream_) | lengthOfSourceStream (lengthOfSourceStream_) | ||||
{ | { | ||||
setPosition (0); | |||||
SubregionStream::setPosition (0); | |||||
} | } | ||||
SubregionStream::~SubregionStream() | SubregionStream::~SubregionStream() | ||||
@@ -676,91 +676,79 @@ bool BigInteger::operator> (const BigInteger& other) const noexcept { return | |||||
bool BigInteger::operator>= (const BigInteger& other) const noexcept { return compare (other) >= 0; } | bool BigInteger::operator>= (const BigInteger& other) const noexcept { return compare (other) >= 0; } | ||||
//============================================================================== | //============================================================================== | ||||
void BigInteger::shiftBits (int bits, const int startBit) | |||||
void BigInteger::shiftLeft (int bits, const int startBit) | |||||
{ | { | ||||
if (highestBit < 0) | |||||
return; | |||||
if (startBit > 0) | if (startBit > 0) | ||||
{ | { | ||||
if (bits < 0) | |||||
{ | |||||
// right shift | |||||
for (int i = startBit; i <= highestBit; ++i) | |||||
setBit (i, operator[] (i - bits)); | |||||
for (int i = highestBit + 1; --i >= startBit;) | |||||
setBit (i + bits, operator[] (i)); | |||||
highestBit = getHighestBit(); | |||||
} | |||||
else if (bits > 0) | |||||
{ | |||||
// left shift | |||||
for (int i = highestBit + 1; --i >= startBit;) | |||||
setBit (i + bits, operator[] (i)); | |||||
while (--bits >= 0) | |||||
clearBit (bits + startBit); | |||||
} | |||||
while (--bits >= 0) | |||||
clearBit (bits + startBit); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
if (bits < 0) | |||||
ensureSize (bitToIndex (highestBit + bits) + 1); | |||||
const int wordsToMove = bitToIndex (bits); | |||||
int top = 1 + bitToIndex (highestBit); | |||||
highestBit += bits; | |||||
if (wordsToMove > 0) | |||||
{ | { | ||||
// right shift | |||||
bits = -bits; | |||||
int i; | |||||
for (i = top; --i >= 0;) | |||||
values [i + wordsToMove] = values [i]; | |||||
if (bits > highestBit) | |||||
{ | |||||
clear(); | |||||
} | |||||
else | |||||
{ | |||||
const int wordsToMove = bitToIndex (bits); | |||||
int top = 1 + bitToIndex (highestBit) - wordsToMove; | |||||
highestBit -= bits; | |||||
for (i = 0; i < wordsToMove; ++i) | |||||
values [i] = 0; | |||||
if (wordsToMove > 0) | |||||
{ | |||||
int i; | |||||
for (i = 0; i < top; ++i) | |||||
values [i] = values [i + wordsToMove]; | |||||
bits &= 31; | |||||
} | |||||
for (i = 0; i < wordsToMove; ++i) | |||||
values [top + i] = 0; | |||||
if (bits != 0) | |||||
{ | |||||
const int invBits = 32 - bits; | |||||
bits &= 31; | |||||
} | |||||
for (int i = top + 1 + wordsToMove; --i > wordsToMove;) | |||||
values[i] = (values[i] << bits) | (values [i - 1] >> invBits); | |||||
if (bits != 0) | |||||
{ | |||||
const int invBits = 32 - bits; | |||||
values [wordsToMove] = values [wordsToMove] << bits; | |||||
} | |||||
--top; | |||||
for (int i = 0; i < top; ++i) | |||||
values[i] = (values[i] >> bits) | (values [i + 1] << invBits); | |||||
highestBit = getHighestBit(); | |||||
} | |||||
} | |||||
values[top] = (values[top] >> bits); | |||||
} | |||||
void BigInteger::shiftRight (int bits, const int startBit) | |||||
{ | |||||
if (startBit > 0) | |||||
{ | |||||
for (int i = startBit; i <= highestBit; ++i) | |||||
setBit (i, operator[] (i + bits)); | |||||
highestBit = getHighestBit(); | |||||
} | |||||
highestBit = getHighestBit(); | |||||
} | |||||
else | |||||
{ | |||||
if (bits > highestBit) | |||||
{ | |||||
clear(); | |||||
} | } | ||||
else if (bits > 0) | |||||
else | |||||
{ | { | ||||
// left shift | |||||
ensureSize (bitToIndex (highestBit + bits) + 1); | |||||
const int wordsToMove = bitToIndex (bits); | const int wordsToMove = bitToIndex (bits); | ||||
int top = 1 + bitToIndex (highestBit); | |||||
highestBit += bits; | |||||
int top = 1 + bitToIndex (highestBit) - wordsToMove; | |||||
highestBit -= bits; | |||||
if (wordsToMove > 0) | if (wordsToMove > 0) | ||||
{ | { | ||||
int i; | int i; | ||||
for (i = top; --i >= 0;) | |||||
values [i + wordsToMove] = values [i]; | |||||
for (i = 0; i < top; ++i) | |||||
values [i] = values [i + wordsToMove]; | |||||
for (i = 0; i < wordsToMove; ++i) | for (i = 0; i < wordsToMove; ++i) | ||||
values [i] = 0; | |||||
values [top + i] = 0; | |||||
bits &= 31; | bits &= 31; | ||||
} | } | ||||
@@ -769,10 +757,11 @@ void BigInteger::shiftBits (int bits, const int startBit) | |||||
{ | { | ||||
const int invBits = 32 - bits; | const int invBits = 32 - bits; | ||||
for (int i = top + 1 + wordsToMove; --i > wordsToMove;) | |||||
values[i] = (values[i] << bits) | (values [i - 1] >> invBits); | |||||
--top; | |||||
for (int i = 0; i < top; ++i) | |||||
values[i] = (values[i] >> bits) | (values [i + 1] << invBits); | |||||
values [wordsToMove] = values [wordsToMove] << bits; | |||||
values[top] = (values[top] >> bits); | |||||
} | } | ||||
highestBit = getHighestBit(); | highestBit = getHighestBit(); | ||||
@@ -780,6 +769,17 @@ void BigInteger::shiftBits (int bits, const int startBit) | |||||
} | } | ||||
} | } | ||||
void BigInteger::shiftBits (int bits, const int startBit) | |||||
{ | |||||
if (highestBit >= 0) | |||||
{ | |||||
if (bits < 0) | |||||
shiftRight (-bits, startBit); | |||||
else if (bits > 0) | |||||
shiftLeft (bits, startBit); | |||||
} | |||||
} | |||||
//============================================================================== | //============================================================================== | ||||
const BigInteger BigInteger::simpleGCD (BigInteger* m, BigInteger* n) | const BigInteger BigInteger::simpleGCD (BigInteger* m, BigInteger* n) | ||||
{ | { | ||||
@@ -311,6 +311,8 @@ private: | |||||
bool negative; | bool negative; | ||||
void ensureSize (int numVals); | void ensureSize (int numVals); | ||||
void shiftLeft (int bits, int startBit); | |||||
void shiftRight (int bits, int startBit); | |||||
static const BigInteger simpleGCD (BigInteger* m, BigInteger* n); | static const BigInteger simpleGCD (BigInteger* m, BigInteger* n); | ||||
static inline int bitToIndex (const int bit) noexcept { return bit >> 5; } | static inline int bitToIndex (const int bit) noexcept { return bit >> 5; } | ||||
@@ -108,8 +108,8 @@ public: | |||||
template <typename CharPointerType> | template <typename CharPointerType> | ||||
static double readDoubleValue (CharPointerType& text) noexcept | static double readDoubleValue (CharPointerType& text) noexcept | ||||
{ | { | ||||
double result[3] = { 0, 0, 0 }, accumulator[2] = { 0, 0 }; | |||||
int exponentAdjustment[2] = { 0, 0 }, exponentAccumulator[2] = { -1, -1 }; | |||||
double result[3] = { 0 }, accumulator[2] = { 0 }; | |||||
int exponentAdjustment[2] = { 0 }, exponentAccumulator[2] = { -1, -1 }; | |||||
int exponent = 0, decPointIndex = 0, digit = 0; | int exponent = 0, decPointIndex = 0, digit = 0; | ||||
int lastDigit = 0, numSignificantDigits = 0; | int lastDigit = 0, numSignificantDigits = 0; | ||||
bool isNegative = false, digitsFound = false; | bool isNegative = false, digitsFound = false; | ||||
@@ -526,7 +526,7 @@ void XmlDocument::readChildElements (XmlElement* parent) | |||||
if (n != nullptr) | if (n != nullptr) | ||||
childAppender.append (n); | childAppender.append (n); | ||||
else | else | ||||
return; | |||||
break; | |||||
} | } | ||||
} | } | ||||
else // must be a character block | else // must be a character block | ||||