@@ -200,7 +200,7 @@ public: | |||
isRunning = false; | |||
timeSliceThread.removeTimeSliceClient (this); | |||
while (useTimeSlice() == 0) | |||
while (writePendingData() == 0) | |||
{} | |||
} | |||
@@ -229,6 +229,11 @@ public: | |||
} | |||
int useTimeSlice() | |||
{ | |||
return writePendingData(); | |||
} | |||
int writePendingData() | |||
{ | |||
const int numToDo = getTotalSize() / 4; | |||
@@ -90,11 +90,6 @@ static const char* const oggExtensions[] = { ".ogg", 0 }; | |||
//============================================================================== | |||
class OggReader : public AudioFormatReader | |||
{ | |||
OggVorbisNamespace::OggVorbis_File ovFile; | |||
OggVorbisNamespace::ov_callbacks callbacks; | |||
AudioSampleBuffer reservoir; | |||
int reservoirStart, samplesInReservoir; | |||
public: | |||
//============================================================================== | |||
OggReader (InputStream* const inp) | |||
@@ -242,33 +237,28 @@ public: | |||
} | |||
private: | |||
OggVorbisNamespace::OggVorbis_File ovFile; | |||
OggVorbisNamespace::ov_callbacks callbacks; | |||
AudioSampleBuffer reservoir; | |||
int reservoirStart, samplesInReservoir; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OggReader); | |||
}; | |||
//============================================================================== | |||
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: | |||
bool ok; | |||
//============================================================================== | |||
OggWriter (OutputStream* const out, | |||
const double sampleRate, | |||
const int numChannels, | |||
const int bitsPerSample, | |||
const int qualityIndex) | |||
: AudioFormatWriter (out, TRANS (oggFormatName), sampleRate, numChannels, bitsPerSample) | |||
: AudioFormatWriter (out, TRANS (oggFormatName), sampleRate, numChannels, bitsPerSample), | |||
ok (false) | |||
{ | |||
using namespace OggVorbisNamespace; | |||
ok = false; | |||
vorbis_info_init (&vi); | |||
@@ -314,7 +304,7 @@ public: | |||
if (ok) | |||
{ | |||
// write a zero-length packet to show ogg that we're finished.. | |||
write (0, 0); | |||
writeSamples (0); | |||
ogg_stream_clear (&os); | |||
vorbis_block_clear (&vb); | |||
@@ -335,28 +325,38 @@ public: | |||
//============================================================================== | |||
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); | |||
while (vorbis_analysis_blockout (&vd, &vb) == 1) | |||
@@ -381,11 +381,19 @@ public: | |||
} | |||
} | |||
} | |||
return true; | |||
} | |||
bool ok; | |||
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); | |||
}; | |||
@@ -43,8 +43,6 @@ AudioFormatReaderSource::AudioFormatReaderSource (AudioFormatReader* const reade | |||
AudioFormatReaderSource::~AudioFormatReaderSource() | |||
{ | |||
releaseResources(); | |||
if (deleteReader) | |||
delete reader; | |||
} | |||
@@ -55,7 +55,7 @@ AudioTransportSource::~AudioTransportSource() | |||
{ | |||
setSource (nullptr); | |||
releaseResources(); | |||
releaseMasterResources(); | |||
} | |||
void AudioTransportSource::setSource (PositionableAudioSource* const newSource, | |||
@@ -242,7 +242,7 @@ void AudioTransportSource::prepareToPlay (int samplesPerBlockExpected, | |||
isPrepared = true; | |||
} | |||
void AudioTransportSource::releaseResources() | |||
void AudioTransportSource::releaseMasterResources() | |||
{ | |||
const ScopedLock sl (callbackLock); | |||
@@ -252,6 +252,11 @@ void AudioTransportSource::releaseResources() | |||
isPrepared = false; | |||
} | |||
void AudioTransportSource::releaseResources() | |||
{ | |||
releaseMasterResources(); | |||
} | |||
void AudioTransportSource::getNextAudioBlock (const AudioSourceChannelInfo& info) | |||
{ | |||
const ScopedLock sl (callbackLock); | |||
@@ -176,6 +176,8 @@ private: | |||
int blockSize, readAheadBufferSize; | |||
bool isPrepared, inputStreamEOF; | |||
void releaseMasterResources(); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioTransportSource); | |||
}; | |||
@@ -301,8 +301,8 @@ int MidiMessage::getChannel() const noexcept | |||
{ | |||
if ((data[0] & 0xf0) != 0xf0) | |||
return (data[0] & 0xf) + 1; | |||
else | |||
return 0; | |||
return 0; | |||
} | |||
bool MidiMessage::isForChannel (const int channel) const noexcept | |||
@@ -355,8 +355,8 @@ uint8 MidiMessage::getVelocity() const noexcept | |||
{ | |||
if (isNoteOnOrOff()) | |||
return data[2]; | |||
else | |||
return 0; | |||
return 0; | |||
} | |||
float MidiMessage::getFloatVelocity() const noexcept | |||
@@ -383,6 +383,7 @@ bool MidiMessage::isAftertouch() const noexcept | |||
int MidiMessage::getAfterTouchValue() const noexcept | |||
{ | |||
jassert (isAftertouch()); | |||
return data[2]; | |||
} | |||
@@ -407,7 +408,6 @@ bool MidiMessage::isChannelPressure() const noexcept | |||
int MidiMessage::getChannelPressureValue() const noexcept | |||
{ | |||
jassert (isChannelPressure()); | |||
return data[1]; | |||
} | |||
@@ -427,6 +427,7 @@ bool MidiMessage::isProgramChange() const noexcept | |||
int MidiMessage::getProgramChangeNumber() const noexcept | |||
{ | |||
jassert (isProgramChange()); | |||
return data[1]; | |||
} | |||
@@ -445,6 +446,7 @@ bool MidiMessage::isPitchWheel() const noexcept | |||
int MidiMessage::getPitchWheelValue() const noexcept | |||
{ | |||
jassert (isPitchWheel()); | |||
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 (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 | |||
@@ -465,14 +468,12 @@ bool MidiMessage::isController() const noexcept | |||
int MidiMessage::getControllerNumber() const noexcept | |||
{ | |||
jassert (isController()); | |||
return data[1]; | |||
} | |||
int MidiMessage::getControllerValue() const noexcept | |||
{ | |||
jassert (isController()); | |||
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 | |||
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 | |||
{ | |||
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 | |||
@@ -494,7 +496,8 @@ const MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, | |||
jassert (channel > 0 && channel <= 16); | |||
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 | |||
@@ -502,7 +505,8 @@ const MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, | |||
jassert (channel > 0 && channel <= 16); | |||
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 | |||
@@ -534,15 +538,10 @@ const MidiMessage MidiMessage::masterVolume (const float volume) | |||
{ | |||
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); | |||
} | |||
@@ -574,17 +573,10 @@ int MidiMessage::getSysExDataSize() const noexcept | |||
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 | |||
{ | |||
return *data != 0xff ? -1 : data[1]; | |||
@@ -603,26 +595,20 @@ int MidiMessage::getMetaEventLength() const noexcept | |||
const uint8* MidiMessage::getMetaEventData() const noexcept | |||
{ | |||
jassert (isMetaEvent()); | |||
int n; | |||
const uint8* d = data + 2; | |||
readVariableLengthVal (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 | |||
{ | |||
const int t = getMetaEventType(); | |||
return t > 0 && t < 16; | |||
} | |||
@@ -631,23 +617,13 @@ const String MidiMessage::getTextFromTextMetaEvent() const | |||
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 | |||
{ | |||
jassert (isMidiChannelMetaEvent()); | |||
return data[3] + 1; | |||
} | |||
@@ -693,13 +669,10 @@ double MidiMessage::getTempoMetaEventTickLength (const short timeFormat) const n | |||
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); | |||
} | |||
@@ -726,12 +699,6 @@ void MidiMessage::getTimeSignatureInfo (int& numerator, int& denominator) const | |||
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 powerOfTwo = 0; | |||
@@ -741,20 +708,15 @@ const MidiMessage MidiMessage::timeSignatureMetaEvent (const int numerator, cons | |||
++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); | |||
} | |||
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); | |||
} | |||
@@ -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 | |||
{ | |||
@@ -792,63 +747,23 @@ const MidiMessage MidiMessage::songPositionPointer (const int positionInMidiBeat | |||
(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); | |||
} | |||
@@ -862,10 +777,7 @@ bool MidiMessage::isFullFrame() const noexcept | |||
&& 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 | |||
{ | |||
jassert (isFullFrame()); | |||
@@ -877,23 +789,16 @@ void MidiMessage::getFullFrameParameters (int& hours, | |||
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) | |||
{ | |||
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); | |||
} | |||
@@ -915,22 +820,13 @@ MidiMessage::MidiMachineControlCommand MidiMessage::getMidiMachineControlCommand | |||
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); | |||
} | |||
//============================================================================== | |||
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 | |||
&& data[0] == 0xf0 | |||
@@ -951,24 +847,14 @@ bool MidiMessage::isMidiMachineControlGoto (int& hours, | |||
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); | |||
} | |||
@@ -55,7 +55,7 @@ PluginListComponent::PluginListComponent (KnownPluginList& listToEdit, | |||
setSize (400, 600); | |||
list.addChangeListener (this); | |||
changeListenerCallback (nullptr); | |||
updateList(); | |||
} | |||
PluginListComponent::~PluginListComponent() | |||
@@ -71,6 +71,11 @@ void PluginListComponent::resized() | |||
} | |||
void PluginListComponent::changeListenerCallback (ChangeBroadcaster*) | |||
{ | |||
updateList(); | |||
} | |||
void PluginListComponent::updateList() | |||
{ | |||
listBox.updateContent(); | |||
listBox.repaint(); | |||
@@ -92,6 +92,7 @@ private: | |||
void scanFor (AudioPluginFormat* format); | |||
static void optionsMenuStaticCallback (int result, PluginListComponent*); | |||
void optionsMenuCallback (int result); | |||
void updateList(); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginListComponent); | |||
}; | |||
@@ -378,16 +378,16 @@ void var::swapWith (var& other) noexcept | |||
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 | |||
@@ -73,16 +73,16 @@ public: | |||
var (ReferenceCountedObject* object); | |||
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; | |||
@@ -55,7 +55,7 @@ FileLogger::FileLogger (const File& logFile_, | |||
<< welcomeMessage << newLine | |||
<< "Log started: " << Time::getCurrentTime().toString (true, true) << newLine; | |||
logMessage (welcome); | |||
FileLogger::logMessage (welcome); | |||
} | |||
FileLogger::~FileLogger() | |||
@@ -45,7 +45,7 @@ ArrowButton::ArrowButton (const String& name, | |||
0.5f, 0.5f)); | |||
setComponentEffect (&shadow); | |||
buttonStateChanged(); | |||
updateShadowAndOffset(); | |||
} | |||
ArrowButton::~ArrowButton() | |||
@@ -66,6 +66,11 @@ void ArrowButton::paintButton (Graphics& g, | |||
} | |||
void ArrowButton::buttonStateChanged() | |||
{ | |||
updateShadowAndOffset(); | |||
} | |||
void ArrowButton::updateShadowAndOffset() | |||
{ | |||
offset = (isDown()) ? 1 : 0; | |||
@@ -72,6 +72,8 @@ private: | |||
Path path; | |||
int offset; | |||
void updateShadowAndOffset(); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ArrowButton); | |||
}; | |||
@@ -59,7 +59,7 @@ ComboBox::ComboBox (const String& name) | |||
noChoicesMessage (TRANS("(no choices)")) | |||
{ | |||
setRepaintsOnMouseActivity (true); | |||
lookAndFeelChanged(); | |||
ComboBox::lookAndFeelChanged(); | |||
currentId.addListener (this); | |||
} | |||
@@ -355,8 +355,8 @@ ListBox::ListBox (const String& name, ListBoxModel* const model_) | |||
{ | |||
addAndMakeVisible (viewport = new ListViewport (*this)); | |||
setWantsKeyboardFocus (true); | |||
colourChanged(); | |||
ListBox::setWantsKeyboardFocus (true); | |||
ListBox::colourChanged(); | |||
} | |||
ListBox::~ListBox() | |||
@@ -52,8 +52,7 @@ public: | |||
void paintContent (Graphics& g, int w, int h) | |||
{ | |||
g.setFont (font); | |||
g.setColour (Colours::black); | |||
g.setColour (findColour (TooltipWindow::textColourId, true)); | |||
g.drawFittedText (text, 0, 0, w, h, Justification::centred, 1); | |||
} | |||
@@ -130,7 +129,7 @@ Slider::Slider (const String& name) | |||
setWantsKeyboardFocus (false); | |||
setRepaintsOnMouseActivity (true); | |||
lookAndFeelChanged(); | |||
Slider::lookAndFeelChanged(); | |||
updateText(); | |||
currentValue.addListener (this); | |||
@@ -1029,8 +1028,7 @@ void Slider::mouseDown (const MouseEvent& e) | |||
{ | |||
mouseWasHidden = false; | |||
incDecDragged = false; | |||
mouseXWhenLastDragged = e.x; | |||
mouseYWhenLastDragged = e.y; | |||
mousePosWhenLastDragged = e.getPosition(); | |||
mouseDragStartX = e.getMouseDownX(); | |||
mouseDragStartY = e.getMouseDownY(); | |||
@@ -1223,8 +1221,8 @@ void Slider::mouseDrag (const MouseEvent& e) | |||
{ | |||
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) | |||
{ | |||
@@ -1329,8 +1327,8 @@ void Slider::mouseDrag (const MouseEvent& e) | |||
{ | |||
const int mouseDiff = (isHorizontal() || style == RotaryHorizontalDrag | |||
|| (style == IncDecButtons && incDecDragDirectionIsHorizontal())) | |||
? e.x - mouseXWhenLastDragged | |||
: e.y - mouseYWhenLastDragged; | |||
? e.x - mousePosWhenLastDragged.getX() | |||
: e.y - mousePosWhenLastDragged.getY(); | |||
const double maxSpeed = jmax (200, sliderRegionSize); | |||
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(); | |||
} | |||
mouseXWhenLastDragged = e.x; | |||
mouseYWhenLastDragged = e.y; | |||
mousePosWhenLastDragged = e.getPosition(); | |||
} | |||
} | |||
@@ -825,7 +825,8 @@ private: | |||
double velocityModeSensitivity, velocityModeOffset, minMaxDiff; | |||
int velocityModeThreshold; | |||
float rotaryStart, rotaryEnd; | |||
int numDecimalPlaces, mouseXWhenLastDragged, mouseYWhenLastDragged; | |||
int numDecimalPlaces; | |||
Point<int> mousePosWhenLastDragged; | |||
int mouseDragStartX, mouseDragStartY; | |||
int sliderRegionStart, sliderRegionSize; | |||
int sliderBeingDragged; | |||
@@ -101,19 +101,7 @@ FileBrowserComponent::FileBrowserComponent (int flags_, | |||
addAndMakeVisible (¤tPathBox); | |||
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); | |||
addAndMakeVisible (&filenameBox); | |||
@@ -271,6 +259,24 @@ void FileBrowserComponent::setRoot (const File& newRootDirectory) | |||
&& 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() | |||
{ | |||
setRoot (getRoot().getParentDirectory()); | |||
@@ -475,7 +481,7 @@ void FileBrowserComponent::comboBoxChanged (ComboBox*) | |||
void FileBrowserComponent::getRoots (StringArray& rootNames, StringArray& rootPaths) | |||
{ | |||
#if JUCE_WINDOWS | |||
#if JUCE_WINDOWS | |||
Array<File> roots; | |||
File::findFileSystemRoots (roots); | |||
rootPaths.clear(); | |||
@@ -511,9 +517,8 @@ void FileBrowserComponent::getRoots (StringArray& rootNames, StringArray& rootPa | |||
rootNames.add ("Documents"); | |||
rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName()); | |||
rootNames.add ("Desktop"); | |||
#endif | |||
#if JUCE_MAC | |||
#elif JUCE_MAC | |||
rootPaths.add (File::getSpecialLocation (File::userHomeDirectory).getFullPathName()); | |||
rootNames.add ("Home folder"); | |||
rootPaths.add (File::getSpecialLocation (File::userDocumentsDirectory).getFullPathName()); | |||
@@ -538,16 +543,15 @@ void FileBrowserComponent::getRoots (StringArray& rootNames, StringArray& rootPa | |||
rootNames.add (volume.getFileName()); | |||
} | |||
} | |||
#endif | |||
#if JUCE_LINUX | |||
#else | |||
rootPaths.add ("/"); | |||
rootNames.add ("/"); | |||
rootPaths.add (File::getSpecialLocation (File::userHomeDirectory).getFullPathName()); | |||
rootNames.add ("Home folder"); | |||
rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName()); | |||
rootNames.add ("Desktop"); | |||
#endif | |||
#endif | |||
} | |||
@@ -212,6 +212,9 @@ protected: | |||
*/ | |||
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: | |||
//============================================================================== | |||
ScopedPointer <DirectoryContentsList> fileList; | |||
@@ -117,7 +117,7 @@ FileChooserDialogBox::FileChooserDialogBox (const String& name, | |||
content->newFolderButton.addListener (this); | |||
content->chooserComponent.addListener (this); | |||
selectionChanged(); | |||
FileChooserDialogBox::selectionChanged(); | |||
} | |||
FileChooserDialogBox::~FileChooserDialogBox() | |||
@@ -127,7 +127,55 @@ namespace KeyPressHelpers | |||
{ "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; | |||
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; | |||
@@ -164,44 +199,28 @@ const KeyPress KeyPress::createFromDescription (const String& desc) | |||
} | |||
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) | |||
{ | |||
// 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); | |||
} | |||
~MidiInputSelectorComponentListBox() | |||
{ | |||
} | |||
int getNumRows() | |||
{ | |||
return items.size(); | |||
@@ -223,7 +219,7 @@ public: | |||
type->scanForDevices(); | |||
setup.manager->addChangeListener (this); | |||
changeListenerCallback (nullptr); | |||
updateAllControls(); | |||
} | |||
~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(); | |||
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 (setup.maxNumOutputChannels > 0 | |||
@@ -505,66 +445,8 @@ public: | |||
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 | |||
{ | |||
@@ -586,6 +468,11 @@ public: | |||
setSize (getWidth(), getLowestY() + 4); | |||
} | |||
void changeListenerCallback (ChangeBroadcaster*) | |||
{ | |||
updateAllControls(); | |||
} | |||
private: | |||
AudioIODeviceType* const type; | |||
const AudioIODeviceType::DeviceSetupDetails setup; | |||
@@ -634,6 +521,133 @@ private: | |||
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: | |||
//============================================================================== | |||
class ChannelSelectorListBox : public ListBox, | |||
@@ -660,10 +674,6 @@ public: | |||
setOutlineThickness (1); | |||
} | |||
~ChannelSelectorListBox() | |||
{ | |||
} | |||
void refresh() | |||
{ | |||
items.clear(); | |||
@@ -712,10 +722,7 @@ public: | |||
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())) | |||
{ | |||
@@ -969,7 +976,7 @@ AudioDeviceSelectorComponent::AudioDeviceSelectorComponent (AudioDeviceManager& | |||
} | |||
deviceManager_.addChangeListener (this); | |||
changeListenerCallback (nullptr); | |||
updateAllControls(); | |||
} | |||
AudioDeviceSelectorComponent::~AudioDeviceSelectorComponent() | |||
@@ -1040,7 +1047,7 @@ void AudioDeviceSelectorComponent::comboBoxChanged (ComboBox* comboBoxThatHasCha | |||
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) | |||
@@ -1050,11 +1057,14 @@ void AudioDeviceSelectorComponent::comboBoxChanged (ComboBox* comboBoxThatHasCha | |||
} | |||
void AudioDeviceSelectorComponent::changeListenerCallback (ChangeBroadcaster*) | |||
{ | |||
updateAllControls(); | |||
} | |||
void AudioDeviceSelectorComponent::updateAllControls() | |||
{ | |||
if (deviceTypeDropDown != nullptr) | |||
{ | |||
deviceTypeDropDown->setText (deviceManager.getCurrentAudioDeviceType(), false); | |||
} | |||
if (audioDeviceSettingsComp == nullptr | |||
|| audioDeviceSettingsCompType != deviceManager.getCurrentAudioDeviceType()) | |||
@@ -107,6 +107,8 @@ private: | |||
ScopedPointer<ComboBox> midiOutputSelector; | |||
ScopedPointer<Label> midiInputsLabel, midiOutputLabel; | |||
void updateAllControls(); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioDeviceSelectorComponent); | |||
}; | |||
@@ -102,7 +102,7 @@ AlertWindow::AlertWindow (const String& title, | |||
if (! JUCEApplication::isStandaloneApp()) | |||
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); | |||
} | |||
@@ -78,7 +78,7 @@ DocumentWindow::DocumentWindow (const String& title, | |||
{ | |||
setResizeLimits (128, 128, 32768, 32768); | |||
lookAndFeelChanged(); | |||
DocumentWindow::lookAndFeelChanged(); | |||
} | |||
DocumentWindow::~DocumentWindow() | |||
@@ -41,18 +41,12 @@ ResizableWindow::ResizableWindow (const String& name, | |||
ownsContentComponent (false), | |||
resizeToFitContent (false), | |||
fullscreen (false), | |||
lastNonFullScreenPos (50, 50, 256, 256), | |||
constrainer (nullptr) | |||
#if JUCE_DEBUG | |||
, hasBeenResized (false) | |||
#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, | |||
@@ -62,7 +56,6 @@ ResizableWindow::ResizableWindow (const String& name, | |||
ownsContentComponent (false), | |||
resizeToFitContent (false), | |||
fullscreen (false), | |||
lastNonFullScreenPos (50, 50, 256, 256), | |||
constrainer (nullptr) | |||
#if JUCE_DEBUG | |||
, hasBeenResized (false) | |||
@@ -70,10 +63,7 @@ ResizableWindow::ResizableWindow (const String& name, | |||
{ | |||
setBackgroundColour (backgroundColour_); | |||
defaultConstrainer.setMinimumOnscreenAmounts (0x10000, 16, 24, 16); | |||
if (addToDesktop_) | |||
Component::addToDesktop (getDesktopWindowStyleFlags()); | |||
initialise (addToDesktop_); | |||
} | |||
ResizableWindow::~ResizableWindow() | |||
@@ -93,6 +83,16 @@ ResizableWindow::~ResizableWindow() | |||
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 styleFlags = TopLevelWindow::getDesktopWindowStyleFlags(); | |||
@@ -372,6 +372,7 @@ private: | |||
bool hasBeenResized; | |||
#endif | |||
void initialise (bool addToDesktop); | |||
void updateLastPos(); | |||
void setContent (Component* newComp, bool takeOwnership, bool resizeToFit); | |||
@@ -149,7 +149,7 @@ TopLevelWindow::TopLevelWindow (const String& name, | |||
setOpaque (true); | |||
if (addToDesktop_) | |||
Component::addToDesktop (getDesktopWindowStyleFlags()); | |||
Component::addToDesktop (TopLevelWindow::getDesktopWindowStyleFlags()); | |||
else | |||
setDropShadowEnabled (true); | |||
@@ -43,22 +43,17 @@ class GIFLoader | |||
public: | |||
GIFLoader (InputStream& 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 transparent = -1; | |||
if (! getSizeFromHeader (imageWidth, imageHeight)) | |||
return; | |||
if ((imageWidth <= 0) || (imageHeight <= 0)) | |||
if (! (getSizeFromHeader (imageWidth, imageHeight) | |||
&& imageWidth > 0 && imageHeight > 0)) | |||
return; | |||
unsigned char buf [16]; | |||
@@ -112,8 +107,6 @@ public: | |||
} | |||
} | |||
~GIFLoader() {} | |||
Image image; | |||
private: | |||
@@ -125,11 +118,11 @@ private: | |||
int codeSize, setCodeSize; | |||
int maxCode, maxCodeSize; | |||
int firstcode, oldcode; | |||
int clearCode, end_code; | |||
int clearCode, endCode; | |||
enum { maxGifCode = 1 << 12 }; | |||
int table [2] [maxGifCode]; | |||
int stack [2 * maxGifCode]; | |||
int *sp; | |||
int* sp; | |||
bool getSizeFromHeader (int& w, int& h) | |||
{ | |||
@@ -208,40 +201,41 @@ private: | |||
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; | |||
@@ -258,31 +252,21 @@ private: | |||
if (sp > stack) | |||
return *--sp; | |||
int code; | |||
while ((code = getCode (codeSize, false)) >= 0) | |||
{ | |||
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; | |||
maxCodeSize = 2 * clearCode; | |||
maxCode = clearCode + 2; | |||
sp = stack; | |||
firstcode = oldcode = getCode (codeSize, false); | |||
return firstcode; | |||
} | |||
else if (code == end_code) | |||
else if (code == endCode) | |||
{ | |||
if (dataBlockIsZero) | |||
return -2; | |||
@@ -297,7 +281,7 @@ private: | |||
return -2; | |||
} | |||
incode = code; | |||
const int incode = code; | |||
if (code >= maxCode) | |||
{ | |||
@@ -385,10 +369,11 @@ private: | |||
{ | |||
unsigned char c; | |||
if (input.read (&c, 1) != 1 | |||
|| readLZWByte (true, c) < 0) | |||
if (input.read (&c, 1) != 1) | |||
return false; | |||
initialise (c); | |||
if (transparent >= 0) | |||
{ | |||
palette [transparent][0] = 0; | |||
@@ -404,7 +389,7 @@ private: | |||
uint8* p = destData.data; | |||
const bool hasAlpha = image.hasAlphaChannel(); | |||
while ((index = readLZWByte (false, c)) >= 0) | |||
while ((index = readLZWByte (c)) >= 0) | |||
{ | |||
const uint8* const paletteEntry = palette [index]; | |||
@@ -47,7 +47,8 @@ FileOutputStream::FileOutputStream (const File& f, const int bufferSize_) | |||
FileOutputStream::~FileOutputStream() | |||
{ | |||
flush(); | |||
flushBuffer(); | |||
flushInternal(); | |||
closeHandle(); | |||
} | |||
@@ -60,21 +61,29 @@ bool FileOutputStream::setPosition (int64 newPosition) | |||
{ | |||
if (newPosition != currentPosition) | |||
{ | |||
flush(); | |||
flushBuffer(); | |||
currentPosition = juce_fileSetPosition (fileHandle, newPosition); | |||
} | |||
return newPosition == currentPosition; | |||
} | |||
void FileOutputStream::flush() | |||
bool FileOutputStream::flushBuffer() | |||
{ | |||
bool ok = true; | |||
if (bytesInBuffer > 0) | |||
{ | |||
writeInternal (buffer, bytesInBuffer); | |||
ok = writeInternal (buffer, bytesInBuffer); | |||
bytesInBuffer = 0; | |||
} | |||
return ok; | |||
} | |||
void FileOutputStream::flush() | |||
{ | |||
flushBuffer(); | |||
flushInternal(); | |||
} | |||
@@ -88,15 +97,8 @@ bool FileOutputStream::write (const void* const src, const int numBytes) | |||
} | |||
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) | |||
{ | |||
@@ -97,6 +97,7 @@ private: | |||
void openHandle(); | |||
void closeHandle(); | |||
void flushInternal(); | |||
bool flushBuffer(); | |||
int64 setPositionInternal (int64 newPosition); | |||
int writeInternal (const void* data, int numBytes); | |||
@@ -143,11 +143,11 @@ GZIPCompressorOutputStream::GZIPCompressorOutputStream (OutputStream* const dest | |||
GZIPCompressorOutputStream::~GZIPCompressorOutputStream() | |||
{ | |||
flush(); | |||
flushInternal(); | |||
} | |||
//============================================================================== | |||
void GZIPCompressorOutputStream::flush() | |||
void GZIPCompressorOutputStream::flushInternal() | |||
{ | |||
if (! helper->finished) | |||
{ | |||
@@ -160,6 +160,11 @@ void GZIPCompressorOutputStream::flush() | |||
destStream->flush(); | |||
} | |||
void GZIPCompressorOutputStream::flush() | |||
{ | |||
flushInternal(); | |||
} | |||
bool GZIPCompressorOutputStream::write (const void* destBuffer, int howMany) | |||
{ | |||
if (! helper->finished) | |||
@@ -85,6 +85,7 @@ private: | |||
friend class ScopedPointer <GZIPCompressorHelper>; | |||
ScopedPointer <GZIPCompressorHelper> helper; | |||
bool doNextBlock(); | |||
void flushInternal(); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GZIPCompressorOutputStream); | |||
}; | |||
@@ -51,10 +51,15 @@ MemoryOutputStream::MemoryOutputStream (MemoryBlock& memoryBlockToWriteTo, | |||
MemoryOutputStream::~MemoryOutputStream() | |||
{ | |||
flush(); | |||
trimExternalBlockSize(); | |||
} | |||
void MemoryOutputStream::flush() | |||
{ | |||
trimExternalBlockSize(); | |||
} | |||
void MemoryOutputStream::trimExternalBlockSize() | |||
{ | |||
if (&data != &internalBlock) | |||
data.setSize (size, false); | |||
@@ -116,6 +116,8 @@ private: | |||
MemoryBlock internalBlock; | |||
size_t position, size; | |||
void trimExternalBlockSize(); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryOutputStream); | |||
}; | |||
@@ -39,7 +39,7 @@ SubregionStream::SubregionStream (InputStream* const sourceStream, | |||
startPositionInSourceStream (startPositionInSourceStream_), | |||
lengthOfSourceStream (lengthOfSourceStream_) | |||
{ | |||
setPosition (0); | |||
SubregionStream::setPosition (0); | |||
} | |||
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; } | |||
//============================================================================== | |||
void BigInteger::shiftBits (int bits, const int startBit) | |||
void BigInteger::shiftLeft (int bits, const int startBit) | |||
{ | |||
if (highestBit < 0) | |||
return; | |||
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 | |||
{ | |||
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); | |||
int top = 1 + bitToIndex (highestBit); | |||
highestBit += bits; | |||
int top = 1 + bitToIndex (highestBit) - wordsToMove; | |||
highestBit -= bits; | |||
if (wordsToMove > 0) | |||
{ | |||
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) | |||
values [i] = 0; | |||
values [top + i] = 0; | |||
bits &= 31; | |||
} | |||
@@ -769,10 +757,11 @@ void BigInteger::shiftBits (int bits, const int startBit) | |||
{ | |||
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(); | |||
@@ -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) | |||
{ | |||
@@ -311,6 +311,8 @@ private: | |||
bool negative; | |||
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 inline int bitToIndex (const int bit) noexcept { return bit >> 5; } | |||
@@ -108,8 +108,8 @@ public: | |||
template <typename CharPointerType> | |||
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 lastDigit = 0, numSignificantDigits = 0; | |||
bool isNegative = false, digitsFound = false; | |||
@@ -526,7 +526,7 @@ void XmlDocument::readChildElements (XmlElement* parent) | |||
if (n != nullptr) | |||
childAppender.append (n); | |||
else | |||
return; | |||
break; | |||
} | |||
} | |||
else // must be a character block | |||