| @@ -1,486 +1,487 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../juce_Config.h" | |||
| #if JUCE_ALSA | |||
| #include "../../../src/juce_core/basics/juce_StandardHeader.h" | |||
| #include <alsa/asoundlib.h> | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "../../../src/juce_appframework/audio/devices/juce_MidiOutput.h" | |||
| #include "../../../src/juce_appframework/audio/devices/juce_MidiInput.h" | |||
| #include "../../../src/juce_core/threads/juce_Thread.h" | |||
| #include "../../../src/juce_core/basics/juce_Time.h" | |||
| //============================================================================== | |||
| static snd_seq_t* iterateDevices (const bool forInput, | |||
| StringArray& deviceNamesFound, | |||
| const int deviceIndexToOpen) | |||
| { | |||
| snd_seq_t* returnedHandle = 0; | |||
| snd_seq_t* seqHandle; | |||
| if (snd_seq_open (&seqHandle, "default", forInput ? SND_SEQ_OPEN_INPUT | |||
| : SND_SEQ_OPEN_OUTPUT, 0) == 0) | |||
| { | |||
| snd_seq_system_info_t* systemInfo; | |||
| snd_seq_client_info_t* clientInfo; | |||
| if (snd_seq_system_info_malloc (&systemInfo) == 0) | |||
| { | |||
| if (snd_seq_system_info (seqHandle, systemInfo) == 0 | |||
| && snd_seq_client_info_malloc (&clientInfo) == 0) | |||
| { | |||
| int numClients = snd_seq_system_info_get_cur_clients (systemInfo); | |||
| while (--numClients >= 0 && returnedHandle == 0) | |||
| { | |||
| if (snd_seq_query_next_client (seqHandle, clientInfo) == 0) | |||
| { | |||
| snd_seq_port_info_t* portInfo; | |||
| if (snd_seq_port_info_malloc (&portInfo) == 0) | |||
| { | |||
| int numPorts = snd_seq_client_info_get_num_ports (clientInfo); | |||
| const int client = snd_seq_client_info_get_client (clientInfo); | |||
| snd_seq_port_info_set_client (portInfo, client); | |||
| snd_seq_port_info_set_port (portInfo, -1); | |||
| while (--numPorts >= 0) | |||
| { | |||
| if (snd_seq_query_next_port (seqHandle, portInfo) == 0 | |||
| && (snd_seq_port_info_get_capability (portInfo) | |||
| & (forInput ? SND_SEQ_PORT_CAP_READ | |||
| : SND_SEQ_PORT_CAP_WRITE)) != 0) | |||
| { | |||
| deviceNamesFound.add (snd_seq_client_info_get_name (clientInfo)); | |||
| if (deviceNamesFound.size() == deviceIndexToOpen + 1) | |||
| { | |||
| const int sourcePort = snd_seq_port_info_get_port (portInfo); | |||
| const int sourceClient = snd_seq_client_info_get_client (clientInfo); | |||
| if (sourcePort != -1) | |||
| { | |||
| snd_seq_set_client_name (seqHandle, | |||
| forInput ? "Juce Midi Input" | |||
| : "Juce Midi Output"); | |||
| const int portId | |||
| = snd_seq_create_simple_port (seqHandle, | |||
| forInput ? "Juce Midi In Port" | |||
| : "Juce Midi Out Port", | |||
| forInput ? (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE) | |||
| : (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ), | |||
| SND_SEQ_PORT_TYPE_MIDI_GENERIC); | |||
| snd_seq_connect_from (seqHandle, portId, sourceClient, sourcePort); | |||
| returnedHandle = seqHandle; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| snd_seq_port_info_free (portInfo); | |||
| } | |||
| } | |||
| } | |||
| snd_seq_client_info_free (clientInfo); | |||
| } | |||
| snd_seq_system_info_free (systemInfo); | |||
| } | |||
| if (returnedHandle == 0) | |||
| snd_seq_close (seqHandle); | |||
| } | |||
| deviceNamesFound.appendNumbersToDuplicates (true, true); | |||
| return returnedHandle; | |||
| } | |||
| static snd_seq_t* createDevice (const bool forInput, | |||
| const String& deviceNameToOpen) | |||
| { | |||
| snd_seq_t* seqHandle = 0; | |||
| if (snd_seq_open (&seqHandle, "default", forInput ? SND_SEQ_OPEN_INPUT | |||
| : SND_SEQ_OPEN_OUTPUT, 0) == 0) | |||
| { | |||
| snd_seq_set_client_name (seqHandle, | |||
| (const char*) (forInput ? (deviceNameToOpen + T(" Input")) | |||
| : (deviceNameToOpen + T(" Output")))); | |||
| const int portId | |||
| = snd_seq_create_simple_port (seqHandle, | |||
| forInput ? "in" | |||
| : "out", | |||
| forInput ? (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE) | |||
| : (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ), | |||
| forInput ? SND_SEQ_PORT_TYPE_APPLICATION | |||
| : SND_SEQ_PORT_TYPE_MIDI_GENERIC); | |||
| if (portId < 0) | |||
| { | |||
| snd_seq_close (seqHandle); | |||
| seqHandle = 0; | |||
| } | |||
| } | |||
| return seqHandle; | |||
| } | |||
| //============================================================================== | |||
| class MidiOutputDevice | |||
| { | |||
| public: | |||
| MidiOutputDevice (MidiOutput* const midiOutput_, | |||
| snd_seq_t* const seqHandle_) | |||
| : | |||
| midiOutput (midiOutput_), | |||
| seqHandle (seqHandle_), | |||
| maxEventSize (16 * 1024) | |||
| { | |||
| jassert (seqHandle != 0 && midiOutput != 0); | |||
| snd_midi_event_new (maxEventSize, &midiParser); | |||
| } | |||
| ~MidiOutputDevice() | |||
| { | |||
| snd_midi_event_free (midiParser); | |||
| snd_seq_close (seqHandle); | |||
| } | |||
| void sendMessageNow (const MidiMessage& message) | |||
| { | |||
| if (message.getRawDataSize() > maxEventSize) | |||
| { | |||
| maxEventSize = message.getRawDataSize(); | |||
| snd_midi_event_free (midiParser); | |||
| snd_midi_event_new (maxEventSize, &midiParser); | |||
| } | |||
| snd_seq_event_t event; | |||
| snd_seq_ev_clear (&event); | |||
| snd_midi_event_encode (midiParser, | |||
| message.getRawData(), | |||
| message.getRawDataSize(), | |||
| &event); | |||
| snd_midi_event_reset_encode (midiParser); | |||
| snd_seq_ev_set_source (&event, 0); | |||
| snd_seq_ev_set_subs (&event); | |||
| snd_seq_ev_set_direct (&event); | |||
| snd_seq_event_output_direct (seqHandle, &event); | |||
| } | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| MidiOutput* const midiOutput; | |||
| snd_seq_t* const seqHandle; | |||
| snd_midi_event_t* midiParser; | |||
| int maxEventSize; | |||
| }; | |||
| const StringArray MidiOutput::getDevices() | |||
| { | |||
| StringArray devices; | |||
| iterateDevices (false, devices, -1); | |||
| return devices; | |||
| } | |||
| int MidiOutput::getDefaultDeviceIndex() | |||
| { | |||
| return 0; | |||
| } | |||
| MidiOutput* MidiOutput::openDevice (int deviceIndex) | |||
| { | |||
| MidiOutput* newDevice = 0; | |||
| StringArray devices; | |||
| snd_seq_t* const handle = iterateDevices (false, devices, deviceIndex); | |||
| if (handle != 0) | |||
| { | |||
| newDevice = new MidiOutput(); | |||
| newDevice->internal = new MidiOutputDevice (newDevice, handle); | |||
| } | |||
| return newDevice; | |||
| } | |||
| MidiOutput* MidiOutput::createNewDevice (const String& deviceName) | |||
| { | |||
| MidiOutput* newDevice = 0; | |||
| snd_seq_t* const handle = createDevice (false, deviceName); | |||
| if (handle != 0) | |||
| { | |||
| newDevice = new MidiOutput(); | |||
| newDevice->internal = new MidiOutputDevice (newDevice, handle); | |||
| } | |||
| return newDevice; | |||
| } | |||
| MidiOutput::~MidiOutput() | |||
| { | |||
| MidiOutputDevice* const device = (MidiOutputDevice*) internal; | |||
| delete device; | |||
| } | |||
| void MidiOutput::reset() | |||
| { | |||
| } | |||
| bool MidiOutput::getVolume (float& leftVol, float& rightVol) | |||
| { | |||
| return false; | |||
| } | |||
| void MidiOutput::setVolume (float leftVol, float rightVol) | |||
| { | |||
| } | |||
| void MidiOutput::sendMessageNow (const MidiMessage& message) | |||
| { | |||
| ((MidiOutputDevice*) internal)->sendMessageNow (message); | |||
| } | |||
| //============================================================================== | |||
| class MidiInputThread : public Thread | |||
| { | |||
| public: | |||
| MidiInputThread (MidiInput* const midiInput_, | |||
| snd_seq_t* const seqHandle_, | |||
| MidiInputCallback* const callback_) | |||
| : Thread (T("Juce MIDI Input")), | |||
| midiInput (midiInput_), | |||
| seqHandle (seqHandle_), | |||
| callback (callback_) | |||
| { | |||
| jassert (seqHandle != 0 && callback != 0 && midiInput != 0); | |||
| } | |||
| ~MidiInputThread() | |||
| { | |||
| snd_seq_close (seqHandle); | |||
| } | |||
| void run() | |||
| { | |||
| const int maxEventSize = 16 * 1024; | |||
| snd_midi_event_t* midiParser; | |||
| if (snd_midi_event_new (maxEventSize, &midiParser) >= 0) | |||
| { | |||
| uint8* const buffer = (uint8*) juce_malloc (maxEventSize); | |||
| const int numPfds = snd_seq_poll_descriptors_count (seqHandle, POLLIN); | |||
| struct pollfd* const pfd = (struct pollfd*) alloca (numPfds * sizeof (struct pollfd)); | |||
| snd_seq_poll_descriptors (seqHandle, pfd, numPfds, POLLIN); | |||
| while (! threadShouldExit()) | |||
| { | |||
| if (poll (pfd, numPfds, 500) > 0) | |||
| { | |||
| snd_seq_event_t* inputEvent = 0; | |||
| snd_seq_nonblock (seqHandle, 1); | |||
| do | |||
| { | |||
| if (snd_seq_event_input (seqHandle, &inputEvent) >= 0) | |||
| { | |||
| // xxx what about SYSEXes that are too big for the buffer? | |||
| const int numBytes = snd_midi_event_decode (midiParser, buffer, maxEventSize, inputEvent); | |||
| snd_midi_event_reset_decode (midiParser); | |||
| if (numBytes > 0) | |||
| { | |||
| const MidiMessage message ((const uint8*) buffer, | |||
| numBytes, | |||
| Time::getMillisecondCounter() * 0.001); | |||
| callback->handleIncomingMidiMessage (midiInput, message); | |||
| } | |||
| snd_seq_free_event (inputEvent); | |||
| } | |||
| } | |||
| while (snd_seq_event_input_pending (seqHandle, 0) > 0); | |||
| snd_seq_free_event (inputEvent); | |||
| } | |||
| } | |||
| snd_midi_event_free (midiParser); | |||
| juce_free (buffer); | |||
| } | |||
| }; | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| MidiInput* const midiInput; | |||
| snd_seq_t* const seqHandle; | |||
| MidiInputCallback* const callback; | |||
| }; | |||
| //============================================================================== | |||
| MidiInput::MidiInput (const String& name_) | |||
| : name (name_), | |||
| internal (0) | |||
| { | |||
| } | |||
| MidiInput::~MidiInput() | |||
| { | |||
| stop(); | |||
| MidiInputThread* const thread = (MidiInputThread*) internal; | |||
| delete thread; | |||
| } | |||
| void MidiInput::start() | |||
| { | |||
| ((MidiInputThread*) internal)->startThread(); | |||
| } | |||
| void MidiInput::stop() | |||
| { | |||
| ((MidiInputThread*) internal)->stopThread (3000); | |||
| } | |||
| int MidiInput::getDefaultDeviceIndex() | |||
| { | |||
| return 0; | |||
| } | |||
| const StringArray MidiInput::getDevices() | |||
| { | |||
| StringArray devices; | |||
| iterateDevices (true, devices, -1); | |||
| return devices; | |||
| } | |||
| MidiInput* MidiInput::openDevice (int deviceIndex, MidiInputCallback* callback) | |||
| { | |||
| MidiInput* newDevice = 0; | |||
| StringArray devices; | |||
| snd_seq_t* const handle = iterateDevices (true, devices, deviceIndex); | |||
| if (handle != 0) | |||
| { | |||
| newDevice = new MidiInput (devices [deviceIndex]); | |||
| newDevice->internal = new MidiInputThread (newDevice, handle, callback); | |||
| } | |||
| return newDevice; | |||
| } | |||
| MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback) | |||
| { | |||
| MidiInput* newDevice = 0; | |||
| snd_seq_t* const handle = createDevice (true, deviceName); | |||
| if (handle != 0) | |||
| { | |||
| newDevice = new MidiInput (deviceName); | |||
| newDevice->internal = new MidiInputThread (newDevice, handle, callback); | |||
| } | |||
| return newDevice; | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| #else | |||
| //============================================================================== | |||
| // (These are just stub functions if ALSA is unavailable...) | |||
| #include "../../../src/juce_core/basics/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "../../../src/juce_appframework/audio/devices/juce_MidiOutput.h" | |||
| #include "../../../src/juce_appframework/audio/devices/juce_MidiInput.h" | |||
| //============================================================================== | |||
| const StringArray MidiOutput::getDevices() { return StringArray(); } | |||
| int MidiOutput::getDefaultDeviceIndex() { return 0; } | |||
| MidiOutput* MidiOutput::openDevice (int) { return 0; } | |||
| MidiOutput* MidiOutput::createNewDevice (const String&) { return 0; } | |||
| MidiOutput::~MidiOutput() {} | |||
| void MidiOutput::reset() {} | |||
| bool MidiOutput::getVolume (float&, float&) { return false; } | |||
| void MidiOutput::setVolume (float, float) {} | |||
| void MidiOutput::sendMessageNow (const MidiMessage&) {} | |||
| MidiInput::MidiInput (const String& name_) | |||
| : name (name_), | |||
| internal (0) | |||
| {} | |||
| MidiInput::~MidiInput() {} | |||
| void MidiInput::start() {} | |||
| void MidiInput::stop() {} | |||
| int MidiInput::getDefaultDeviceIndex() { return 0; } | |||
| const StringArray MidiInput::getDevices() { return StringArray(); } | |||
| MidiInput* MidiInput::openDevice (int, MidiInputCallback*) { return 0; } | |||
| MidiInput* MidiInput::createNewDevice (const String&, MidiInputCallback*) { return 0; } | |||
| END_JUCE_NAMESPACE | |||
| #endif | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../juce_Config.h" | |||
| #if JUCE_ALSA | |||
| #include "../../../src/juce_core/basics/juce_StandardHeader.h" | |||
| #include <alsa/asoundlib.h> | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "../../../src/juce_appframework/audio/devices/juce_MidiOutput.h" | |||
| #include "../../../src/juce_appframework/audio/devices/juce_MidiInput.h" | |||
| #include "../../../src/juce_core/threads/juce_Thread.h" | |||
| #include "../../../src/juce_core/basics/juce_Time.h" | |||
| //============================================================================== | |||
| static snd_seq_t* iterateDevices (const bool forInput, | |||
| StringArray& deviceNamesFound, | |||
| const int deviceIndexToOpen) | |||
| { | |||
| snd_seq_t* returnedHandle = 0; | |||
| snd_seq_t* seqHandle; | |||
| if (snd_seq_open (&seqHandle, "default", forInput ? SND_SEQ_OPEN_INPUT | |||
| : SND_SEQ_OPEN_OUTPUT, 0) == 0) | |||
| { | |||
| snd_seq_system_info_t* systemInfo; | |||
| snd_seq_client_info_t* clientInfo; | |||
| if (snd_seq_system_info_malloc (&systemInfo) == 0) | |||
| { | |||
| if (snd_seq_system_info (seqHandle, systemInfo) == 0 | |||
| && snd_seq_client_info_malloc (&clientInfo) == 0) | |||
| { | |||
| int numClients = snd_seq_system_info_get_cur_clients (systemInfo); | |||
| while (--numClients >= 0 && returnedHandle == 0) | |||
| { | |||
| if (snd_seq_query_next_client (seqHandle, clientInfo) == 0) | |||
| { | |||
| snd_seq_port_info_t* portInfo; | |||
| if (snd_seq_port_info_malloc (&portInfo) == 0) | |||
| { | |||
| int numPorts = snd_seq_client_info_get_num_ports (clientInfo); | |||
| const int client = snd_seq_client_info_get_client (clientInfo); | |||
| snd_seq_port_info_set_client (portInfo, client); | |||
| snd_seq_port_info_set_port (portInfo, -1); | |||
| while (--numPorts >= 0) | |||
| { | |||
| if (snd_seq_query_next_port (seqHandle, portInfo) == 0 | |||
| && (snd_seq_port_info_get_capability (portInfo) | |||
| & (forInput ? SND_SEQ_PORT_CAP_READ | |||
| : SND_SEQ_PORT_CAP_WRITE)) != 0) | |||
| { | |||
| deviceNamesFound.add (snd_seq_client_info_get_name (clientInfo)); | |||
| if (deviceNamesFound.size() == deviceIndexToOpen + 1) | |||
| { | |||
| const int sourcePort = snd_seq_port_info_get_port (portInfo); | |||
| const int sourceClient = snd_seq_client_info_get_client (clientInfo); | |||
| if (sourcePort != -1) | |||
| { | |||
| snd_seq_set_client_name (seqHandle, | |||
| forInput ? "Juce Midi Input" | |||
| : "Juce Midi Output"); | |||
| const int portId | |||
| = snd_seq_create_simple_port (seqHandle, | |||
| forInput ? "Juce Midi In Port" | |||
| : "Juce Midi Out Port", | |||
| forInput ? (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE) | |||
| : (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ), | |||
| SND_SEQ_PORT_TYPE_MIDI_GENERIC); | |||
| snd_seq_connect_from (seqHandle, portId, sourceClient, sourcePort); | |||
| returnedHandle = seqHandle; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| snd_seq_port_info_free (portInfo); | |||
| } | |||
| } | |||
| } | |||
| snd_seq_client_info_free (clientInfo); | |||
| } | |||
| snd_seq_system_info_free (systemInfo); | |||
| } | |||
| if (returnedHandle == 0) | |||
| snd_seq_close (seqHandle); | |||
| } | |||
| deviceNamesFound.appendNumbersToDuplicates (true, true); | |||
| return returnedHandle; | |||
| } | |||
| static snd_seq_t* createDevice (const bool forInput, | |||
| const String& deviceNameToOpen) | |||
| { | |||
| snd_seq_t* seqHandle = 0; | |||
| if (snd_seq_open (&seqHandle, "default", forInput ? SND_SEQ_OPEN_INPUT | |||
| : SND_SEQ_OPEN_OUTPUT, 0) == 0) | |||
| { | |||
| snd_seq_set_client_name (seqHandle, | |||
| (const char*) (forInput ? (deviceNameToOpen + T(" Input")) | |||
| : (deviceNameToOpen + T(" Output")))); | |||
| const int portId | |||
| = snd_seq_create_simple_port (seqHandle, | |||
| forInput ? "in" | |||
| : "out", | |||
| forInput ? (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE) | |||
| : (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ), | |||
| forInput ? SND_SEQ_PORT_TYPE_APPLICATION | |||
| : SND_SEQ_PORT_TYPE_MIDI_GENERIC); | |||
| if (portId < 0) | |||
| { | |||
| snd_seq_close (seqHandle); | |||
| seqHandle = 0; | |||
| } | |||
| } | |||
| return seqHandle; | |||
| } | |||
| //============================================================================== | |||
| class MidiOutputDevice | |||
| { | |||
| public: | |||
| MidiOutputDevice (MidiOutput* const midiOutput_, | |||
| snd_seq_t* const seqHandle_) | |||
| : | |||
| midiOutput (midiOutput_), | |||
| seqHandle (seqHandle_), | |||
| maxEventSize (16 * 1024) | |||
| { | |||
| jassert (seqHandle != 0 && midiOutput != 0); | |||
| snd_midi_event_new (maxEventSize, &midiParser); | |||
| } | |||
| ~MidiOutputDevice() | |||
| { | |||
| snd_midi_event_free (midiParser); | |||
| snd_seq_close (seqHandle); | |||
| } | |||
| void sendMessageNow (const MidiMessage& message) | |||
| { | |||
| if (message.getRawDataSize() > maxEventSize) | |||
| { | |||
| maxEventSize = message.getRawDataSize(); | |||
| snd_midi_event_free (midiParser); | |||
| snd_midi_event_new (maxEventSize, &midiParser); | |||
| } | |||
| snd_seq_event_t event; | |||
| snd_seq_ev_clear (&event); | |||
| snd_midi_event_encode (midiParser, | |||
| message.getRawData(), | |||
| message.getRawDataSize(), | |||
| &event); | |||
| snd_midi_event_reset_encode (midiParser); | |||
| snd_seq_ev_set_source (&event, 0); | |||
| snd_seq_ev_set_subs (&event); | |||
| snd_seq_ev_set_direct (&event); | |||
| snd_seq_event_output (seqHandle, &event); | |||
| snd_seq_drain_output (seqHandle); | |||
| } | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| MidiOutput* const midiOutput; | |||
| snd_seq_t* const seqHandle; | |||
| snd_midi_event_t* midiParser; | |||
| int maxEventSize; | |||
| }; | |||
| const StringArray MidiOutput::getDevices() | |||
| { | |||
| StringArray devices; | |||
| iterateDevices (false, devices, -1); | |||
| return devices; | |||
| } | |||
| int MidiOutput::getDefaultDeviceIndex() | |||
| { | |||
| return 0; | |||
| } | |||
| MidiOutput* MidiOutput::openDevice (int deviceIndex) | |||
| { | |||
| MidiOutput* newDevice = 0; | |||
| StringArray devices; | |||
| snd_seq_t* const handle = iterateDevices (false, devices, deviceIndex); | |||
| if (handle != 0) | |||
| { | |||
| newDevice = new MidiOutput(); | |||
| newDevice->internal = new MidiOutputDevice (newDevice, handle); | |||
| } | |||
| return newDevice; | |||
| } | |||
| MidiOutput* MidiOutput::createNewDevice (const String& deviceName) | |||
| { | |||
| MidiOutput* newDevice = 0; | |||
| snd_seq_t* const handle = createDevice (false, deviceName); | |||
| if (handle != 0) | |||
| { | |||
| newDevice = new MidiOutput(); | |||
| newDevice->internal = new MidiOutputDevice (newDevice, handle); | |||
| } | |||
| return newDevice; | |||
| } | |||
| MidiOutput::~MidiOutput() | |||
| { | |||
| MidiOutputDevice* const device = (MidiOutputDevice*) internal; | |||
| delete device; | |||
| } | |||
| void MidiOutput::reset() | |||
| { | |||
| } | |||
| bool MidiOutput::getVolume (float& leftVol, float& rightVol) | |||
| { | |||
| return false; | |||
| } | |||
| void MidiOutput::setVolume (float leftVol, float rightVol) | |||
| { | |||
| } | |||
| void MidiOutput::sendMessageNow (const MidiMessage& message) | |||
| { | |||
| ((MidiOutputDevice*) internal)->sendMessageNow (message); | |||
| } | |||
| //============================================================================== | |||
| class MidiInputThread : public Thread | |||
| { | |||
| public: | |||
| MidiInputThread (MidiInput* const midiInput_, | |||
| snd_seq_t* const seqHandle_, | |||
| MidiInputCallback* const callback_) | |||
| : Thread (T("Juce MIDI Input")), | |||
| midiInput (midiInput_), | |||
| seqHandle (seqHandle_), | |||
| callback (callback_) | |||
| { | |||
| jassert (seqHandle != 0 && callback != 0 && midiInput != 0); | |||
| } | |||
| ~MidiInputThread() | |||
| { | |||
| snd_seq_close (seqHandle); | |||
| } | |||
| void run() | |||
| { | |||
| const int maxEventSize = 16 * 1024; | |||
| snd_midi_event_t* midiParser; | |||
| if (snd_midi_event_new (maxEventSize, &midiParser) >= 0) | |||
| { | |||
| uint8* const buffer = (uint8*) juce_malloc (maxEventSize); | |||
| const int numPfds = snd_seq_poll_descriptors_count (seqHandle, POLLIN); | |||
| struct pollfd* const pfd = (struct pollfd*) alloca (numPfds * sizeof (struct pollfd)); | |||
| snd_seq_poll_descriptors (seqHandle, pfd, numPfds, POLLIN); | |||
| while (! threadShouldExit()) | |||
| { | |||
| if (poll (pfd, numPfds, 500) > 0) | |||
| { | |||
| snd_seq_event_t* inputEvent = 0; | |||
| snd_seq_nonblock (seqHandle, 1); | |||
| do | |||
| { | |||
| if (snd_seq_event_input (seqHandle, &inputEvent) >= 0) | |||
| { | |||
| // xxx what about SYSEXes that are too big for the buffer? | |||
| const int numBytes = snd_midi_event_decode (midiParser, buffer, maxEventSize, inputEvent); | |||
| snd_midi_event_reset_decode (midiParser); | |||
| if (numBytes > 0) | |||
| { | |||
| const MidiMessage message ((const uint8*) buffer, | |||
| numBytes, | |||
| Time::getMillisecondCounter() * 0.001); | |||
| callback->handleIncomingMidiMessage (midiInput, message); | |||
| } | |||
| snd_seq_free_event (inputEvent); | |||
| } | |||
| } | |||
| while (snd_seq_event_input_pending (seqHandle, 0) > 0); | |||
| snd_seq_free_event (inputEvent); | |||
| } | |||
| } | |||
| snd_midi_event_free (midiParser); | |||
| juce_free (buffer); | |||
| } | |||
| }; | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| MidiInput* const midiInput; | |||
| snd_seq_t* const seqHandle; | |||
| MidiInputCallback* const callback; | |||
| }; | |||
| //============================================================================== | |||
| MidiInput::MidiInput (const String& name_) | |||
| : name (name_), | |||
| internal (0) | |||
| { | |||
| } | |||
| MidiInput::~MidiInput() | |||
| { | |||
| stop(); | |||
| MidiInputThread* const thread = (MidiInputThread*) internal; | |||
| delete thread; | |||
| } | |||
| void MidiInput::start() | |||
| { | |||
| ((MidiInputThread*) internal)->startThread(); | |||
| } | |||
| void MidiInput::stop() | |||
| { | |||
| ((MidiInputThread*) internal)->stopThread (3000); | |||
| } | |||
| int MidiInput::getDefaultDeviceIndex() | |||
| { | |||
| return 0; | |||
| } | |||
| const StringArray MidiInput::getDevices() | |||
| { | |||
| StringArray devices; | |||
| iterateDevices (true, devices, -1); | |||
| return devices; | |||
| } | |||
| MidiInput* MidiInput::openDevice (int deviceIndex, MidiInputCallback* callback) | |||
| { | |||
| MidiInput* newDevice = 0; | |||
| StringArray devices; | |||
| snd_seq_t* const handle = iterateDevices (true, devices, deviceIndex); | |||
| if (handle != 0) | |||
| { | |||
| newDevice = new MidiInput (devices [deviceIndex]); | |||
| newDevice->internal = new MidiInputThread (newDevice, handle, callback); | |||
| } | |||
| return newDevice; | |||
| } | |||
| MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback) | |||
| { | |||
| MidiInput* newDevice = 0; | |||
| snd_seq_t* const handle = createDevice (true, deviceName); | |||
| if (handle != 0) | |||
| { | |||
| newDevice = new MidiInput (deviceName); | |||
| newDevice->internal = new MidiInputThread (newDevice, handle, callback); | |||
| } | |||
| return newDevice; | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| #else | |||
| //============================================================================== | |||
| // (These are just stub functions if ALSA is unavailable...) | |||
| #include "../../../src/juce_core/basics/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "../../../src/juce_appframework/audio/devices/juce_MidiOutput.h" | |||
| #include "../../../src/juce_appframework/audio/devices/juce_MidiInput.h" | |||
| //============================================================================== | |||
| const StringArray MidiOutput::getDevices() { return StringArray(); } | |||
| int MidiOutput::getDefaultDeviceIndex() { return 0; } | |||
| MidiOutput* MidiOutput::openDevice (int) { return 0; } | |||
| MidiOutput* MidiOutput::createNewDevice (const String&) { return 0; } | |||
| MidiOutput::~MidiOutput() {} | |||
| void MidiOutput::reset() {} | |||
| bool MidiOutput::getVolume (float&, float&) { return false; } | |||
| void MidiOutput::setVolume (float, float) {} | |||
| void MidiOutput::sendMessageNow (const MidiMessage&) {} | |||
| MidiInput::MidiInput (const String& name_) | |||
| : name (name_), | |||
| internal (0) | |||
| {} | |||
| MidiInput::~MidiInput() {} | |||
| void MidiInput::start() {} | |||
| void MidiInput::stop() {} | |||
| int MidiInput::getDefaultDeviceIndex() { return 0; } | |||
| const StringArray MidiInput::getDevices() { return StringArray(); } | |||
| MidiInput* MidiInput::openDevice (int, MidiInputCallback*) { return 0; } | |||
| MidiInput* MidiInput::createNewDevice (const String&, MidiInputCallback*) { return 0; } | |||
| END_JUCE_NAMESPACE | |||
| #endif | |||
| @@ -1,149 +1,161 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| // (This file gets included by juce_mac_NativeCode.mm, rather than being | |||
| // compiled on its own). | |||
| #ifdef JUCE_INCLUDED_FILE | |||
| //============================================================================== | |||
| class NSViewComponentInternal : public ComponentMovementWatcher | |||
| { | |||
| Component* const owner; | |||
| NSViewComponentPeer* currentPeer; | |||
| bool wasShowing; | |||
| public: | |||
| NSView* view; | |||
| //============================================================================== | |||
| NSViewComponentInternal (NSView* view_, Component* const owner_) | |||
| : ComponentMovementWatcher (owner_), | |||
| owner (owner_), | |||
| currentPeer (0), | |||
| wasShowing (false), | |||
| view (view_) | |||
| { | |||
| [view retain]; | |||
| if (owner_->isShowing()) | |||
| componentPeerChanged(); | |||
| } | |||
| ~NSViewComponentInternal() | |||
| { | |||
| [view removeFromSuperview]; | |||
| [view release]; | |||
| } | |||
| //============================================================================== | |||
| void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) | |||
| { | |||
| Component* const topComp = owner->getTopLevelComponent(); | |||
| if (topComp->getPeer() != 0) | |||
| { | |||
| int x = 0, y = 0; | |||
| owner->relativePositionToOtherComponent (topComp, x, y); | |||
| NSRect r; | |||
| r.origin.x = (float) x; | |||
| r.origin.y = (float) y; | |||
| r.size.width = (float) owner->getWidth(); | |||
| r.size.height = (float) owner->getHeight(); | |||
| r.origin.y = [[view superview] frame].size.height - (r.origin.y + r.size.height); | |||
| [view setFrame: r]; | |||
| } | |||
| } | |||
| void componentPeerChanged() | |||
| { | |||
| NSViewComponentPeer* const peer = dynamic_cast <NSViewComponentPeer*> (owner->getPeer()); | |||
| if (currentPeer != peer) | |||
| { | |||
| [view removeFromSuperview]; | |||
| currentPeer = peer; | |||
| if (peer != 0) | |||
| { | |||
| [peer->view addSubview: view]; | |||
| componentMovedOrResized (false, false); | |||
| } | |||
| } | |||
| [view setHidden: ! owner->isShowing()]; | |||
| } | |||
| void componentVisibilityChanged (Component&) | |||
| { | |||
| componentPeerChanged(); | |||
| } | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| NSViewComponentInternal (const NSViewComponentInternal&); | |||
| const NSViewComponentInternal& operator= (const NSViewComponentInternal&); | |||
| }; | |||
| //============================================================================== | |||
| NSViewComponent::NSViewComponent() | |||
| : info (0) | |||
| { | |||
| } | |||
| NSViewComponent::~NSViewComponent() | |||
| { | |||
| delete info; | |||
| } | |||
| void NSViewComponent::setView (void* view) | |||
| { | |||
| if (view != getView()) | |||
| { | |||
| deleteAndZero (info); | |||
| if (view != 0) | |||
| info = new NSViewComponentInternal ((NSView*) view, this); | |||
| } | |||
| } | |||
| void* NSViewComponent::getView() const | |||
| { | |||
| return info == 0 ? 0 : info->view; | |||
| } | |||
| void NSViewComponent::paint (Graphics& g) | |||
| { | |||
| } | |||
| #endif | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| // (This file gets included by juce_mac_NativeCode.mm, rather than being | |||
| // compiled on its own). | |||
| #ifdef JUCE_INCLUDED_FILE | |||
| //============================================================================== | |||
| class NSViewComponentInternal : public ComponentMovementWatcher | |||
| { | |||
| Component* const owner; | |||
| NSViewComponentPeer* currentPeer; | |||
| bool wasShowing; | |||
| public: | |||
| NSView* const view; | |||
| //============================================================================== | |||
| NSViewComponentInternal (NSView* const view_, Component* const owner_) | |||
| : ComponentMovementWatcher (owner_), | |||
| owner (owner_), | |||
| currentPeer (0), | |||
| wasShowing (false), | |||
| view (view_) | |||
| { | |||
| [view_ retain]; | |||
| if (owner_->isShowing()) | |||
| componentPeerChanged(); | |||
| } | |||
| ~NSViewComponentInternal() | |||
| { | |||
| [view removeFromSuperview]; | |||
| [view release]; | |||
| } | |||
| //============================================================================== | |||
| void componentMovedOrResized (Component& comp, bool wasMoved, bool wasResized) | |||
| { | |||
| ComponentMovementWatcher::componentMovedOrResized (comp, wasMoved, wasResized); | |||
| // The ComponentMovementWatcher version of this method avoids calling | |||
| // us when the top-level comp is resized, but for an NSView we need to know this | |||
| // because with inverted co-ords, we need to update the position even if the | |||
| // top-left pos hasn't changed | |||
| if (comp.isOnDesktop() && wasResized) | |||
| componentMovedOrResized (wasMoved, wasResized); | |||
| } | |||
| void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) | |||
| { | |||
| Component* const topComp = owner->getTopLevelComponent(); | |||
| if (topComp->getPeer() != 0) | |||
| { | |||
| int x = 0, y = 0; | |||
| owner->relativePositionToOtherComponent (topComp, x, y); | |||
| NSRect r; | |||
| r.origin.x = (float) x; | |||
| r.origin.y = (float) y; | |||
| r.size.width = (float) owner->getWidth(); | |||
| r.size.height = (float) owner->getHeight(); | |||
| r.origin.y = [[view superview] frame].size.height - (r.origin.y + r.size.height); | |||
| [view setFrame: r]; | |||
| } | |||
| } | |||
| void componentPeerChanged() | |||
| { | |||
| NSViewComponentPeer* const peer = dynamic_cast <NSViewComponentPeer*> (owner->getPeer()); | |||
| if (currentPeer != peer) | |||
| { | |||
| [view removeFromSuperview]; | |||
| currentPeer = peer; | |||
| if (peer != 0) | |||
| { | |||
| [peer->view addSubview: view]; | |||
| componentMovedOrResized (false, false); | |||
| } | |||
| } | |||
| [view setHidden: ! owner->isShowing()]; | |||
| } | |||
| void componentVisibilityChanged (Component&) | |||
| { | |||
| componentPeerChanged(); | |||
| } | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| NSViewComponentInternal (const NSViewComponentInternal&); | |||
| const NSViewComponentInternal& operator= (const NSViewComponentInternal&); | |||
| }; | |||
| //============================================================================== | |||
| NSViewComponent::NSViewComponent() | |||
| : info (0) | |||
| { | |||
| } | |||
| NSViewComponent::~NSViewComponent() | |||
| { | |||
| delete info; | |||
| } | |||
| void NSViewComponent::setView (void* view) | |||
| { | |||
| if (view != getView()) | |||
| { | |||
| deleteAndZero (info); | |||
| if (view != 0) | |||
| info = new NSViewComponentInternal ((NSView*) view, this); | |||
| } | |||
| } | |||
| void* NSViewComponent::getView() const | |||
| { | |||
| return info == 0 ? 0 : info->view; | |||
| } | |||
| void NSViewComponent::paint (Graphics& g) | |||
| { | |||
| } | |||
| #endif | |||
| @@ -80,9 +80,23 @@ BEGIN_JUCE_NAMESPACE | |||
| #undef Point | |||
| //============================================================================== | |||
| /** This suffix is used for naming all Obj-C classes that are used inside juce. | |||
| Because of the flat naming structure used by Obj-C, you can get horrible situations where | |||
| two DLLs are loaded into a host, each of which uses classes with the same names, and these get | |||
| cross-linked so that when you make a call to a class that you thought was private, it ends up | |||
| actually calling into a similarly named class in the other module's address space. | |||
| By changing this macro to a unique value, you ensure that all the obj-C classes in your app | |||
| have unique names, and should avoid this problem. | |||
| If you're using the amalgamated version, you can just set this macro to something unique before | |||
| you include juce_amalgamated.cpp. | |||
| */ | |||
| #ifndef JUCE_ObjCExtraSuffix | |||
| #define JUCE_ObjCExtraSuffix 2 | |||
| #define JUCE_ObjCExtraSuffix 3 | |||
| #endif | |||
| #define appendMacro1(a, b, c, d) a ## _ ## b ## _ ## c ## _ ## d | |||
| #define appendMacro2(a, b, c, d) appendMacro1(a, b, c, d) | |||
| #define MakeObjCClassName(rootName) appendMacro2 (rootName, JUCE_MAJOR_VERSION, JUCE_MINOR_VERSION, JUCE_ObjCExtraSuffix) | |||
| @@ -1,300 +1,312 @@ | |||
| The Juce Polymorphic Plugin Project! | |||
| ==================================== | |||
| (c) 2008 by Raw Material Software, visit www.rawmaterialsoftware.com for more info. | |||
| ----------------------------------------------------------------------------------------------------- | |||
| The purpose of this framework is to make is simple to write an audio plugin in a generic | |||
| way, which can then be compiled as a VST, AudioUnit, RTAS, or any combination of these. | |||
| It's "polymorphic" because the output is a single binary module that acts as all of the | |||
| different plugin formats at the same time. This means that you only need to maintain one | |||
| project, and only need to perform one build to create a multi-format plugin. | |||
| Also included are some helper classes that make it easy to create a stand-alone app to | |||
| run your plugin without a host. This might be useful in its own right, but can also be very | |||
| handy when developing your plugin, because you can build, test and debug it without needing | |||
| to keep restarting a 3rd-party host. | |||
| How does it work? | |||
| ================= | |||
| To create your plugin, you just create a subclass of the AudioPluginInstance class to | |||
| perform the processing. And your plugin UI is written like any normal Juce UI component. | |||
| All the platform-specific code is hidden away in wrapper classes that you just add to | |||
| your project - you should (hopefully) never need to even see the inner workings of these. | |||
| Licensing issues | |||
| ================ | |||
| Juce is released under the GPL (Gnu Public License) - this means that you're free to use | |||
| and redistribute it as long as your products are also released under the GPL. Basically | |||
| this means that if you use it, you also have to give away your source code. | |||
| If you want to release a closed-source application, you can buy a commercial license | |||
| that lets you avoid this restriction - see http://www.rawmaterialsoftware.com/juce for more info, | |||
| or see the comments at the top of all the Juce source files. | |||
| If you're building the VST projects or releasing a VST, you'll need have a look at Steinberg's | |||
| developer site to see what licensing rules apply these days. Their website's at | |||
| http://www.steinberg.net | |||
| If you're building an RTAS then you'll need to sign Digidesign's developer license to get | |||
| their SDK. Visit http://www.digidesign.com for more info. | |||
| Getting Started | |||
| =============== | |||
| There's also a 'demo' folder - this contains an example plugin which can be built in all | |||
| the different formats. | |||
| Have a look at the demo classes to see how it works, and then to create a real plugin, | |||
| you'll need to replace the demo files with your own code. | |||
| I've tried to add helpful comments where you might run across common compile errors, to | |||
| help describe what you might be doing wrong, as getting a build set-up for some of these | |||
| formats can be a bit of a pain. Please let me know if you find there's anything missing | |||
| from these instructions or anything I could change to help smooth the build process along | |||
| a bit. | |||
| I'd recommend NOT putting your own plugin code inside the demo plugin directory - it's | |||
| much neater to keep it somewhere separate and to alter the projects to point to your | |||
| files instead of the demo ones. That way when new versions of this library come out, it'll | |||
| make it easier to update to the latest code. | |||
| ----------------------------------------------------------------------------------------------------- | |||
| Prerequisites for building a VST | |||
| ================================ | |||
| - Visit http://www.steinberg.net and jump through whatever hoops are necessary to download | |||
| and install the VST SDK. | |||
| - Make sure your include path contains an entry for the "vstsdk2.4" folder containing the SDK. | |||
| ----------------------------------------------------------------------------------------------------- | |||
| Prerequisites for building an RTAS | |||
| ================================== | |||
| - Contact Digidesign, ask to become a Digidesign Development Partner, sign the relevent | |||
| agreements and NDAs. | |||
| - From the Digidesign website, download their latest Plug-In SDK | |||
| - Install the SDK and build some of the demo plugins to make sure it all works. | |||
| - In Visual Studio: Add all of these to your include path: | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\EffectClasses | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses\Interfaces | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Utilities | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\RTASP_Adapt | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\CoreClasses | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Controls | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Meters | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ViewClasses | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\DSPClasses | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Interfaces | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\common | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\common\Platform | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\SignalProcessing\Public | |||
| C:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugIns\DSPManager\Interfaces | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\SADriver\Interfaces | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\DigiPublic\Interfaces | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\Fic\Interfaces\DAEClient | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\NewFileLibs\Cmn | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\NewFileLibs\DOA | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\AlturaSource\PPC_H | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\AlturaSource\AppSupport | |||
| c:\yourdirectory\PT_80_SDK\AvidCode\AVX2sdk\AVX\avx2\avx2sdk\inc | |||
| C:\yourdirectory\PT_80_SDK\xplat\AVX\avx2\avx2sdk\inc | |||
| - In Visual Studio: Using the Digidesign demo projects in the SDK, make sure you've compiled | |||
| debug and release versions of the following static libraries: | |||
| DAE.lib, DigiExt.lib, DSI.lib, PlugInLib.lib. | |||
| - In XCode: After installing the Digidesign SDK, make sure you've run the config_SDK_for_Mac | |||
| command in the SDK's root directory. This sets up some of the tools that it needs. | |||
| - In XCode: If you're using the Digi files CommonDebugSettings.xcconfig and CommonReleaseSettings.xcconfig, | |||
| then you'll probably have to remove the "-x c++" option from their OTHER_CFLAGS setting, because | |||
| that prevents it compiling obj-C. Also, you might need to comment-out the GCC_PREFIX_HEADER setting, | |||
| unless you can persuade precompiled headers to work (I've never managed to get them working myself..) | |||
| You'll also probably want to add a "MacBag" setting to these files, rather than putting it into | |||
| your project - e.g. "MacBag = /Users/jules/SDKs/PT_80_SDK/MacBag" | |||
| ----------------------------------------------------------------------------------------------------- | |||
| Choosing the formats to build | |||
| ============================= | |||
| Each plugin project needs to contain a JucePluginCharacteristics.h file, which holds all the | |||
| plugin-specific build details. In here, there are three macros that you can set to enable each | |||
| of the available formats: | |||
| #define JucePlugin_Build_VST 1 | |||
| #define JucePlugin_Build_RTAS 1 | |||
| #define JucePlugin_Build_AU 1 | |||
| You can set these to 0 to disable the formats that you don't want to build, and this will avoid | |||
| any compilation problems if, for example, you don't have the appropriate SDK for a particular format. | |||
| ----------------------------------------------------------------------------------------------------- | |||
| Creating a PC VST/RTAS plugin in Visual Studio | |||
| ============================================== | |||
| - First try loading the VST demo project in JuceAudioPlugin/demo/build. Hopefully this | |||
| should build correctly. | |||
| - Create a new, empty, win32 project using Visual Studio. Choose "DLL" as the type of | |||
| product to build | |||
| - If building an RTAS, add to your project all the juce_RTAS_*.cpp files from the wrapper/RTAS folder. | |||
| - If building a VST, add to your project all the juce_VST_*.cpp files from the wrapper/VST folder. | |||
| - Create yourself a JucePluginCharacteristics.h file, starting with a copy of the one in the | |||
| demo project. Go through each item inside it carefully, and set them to the appropriate value | |||
| for your plugin. | |||
| - Under "Additional Include Directories", add the folder in which you're going to put | |||
| your JucePluginCharacteristics.h file. | |||
| - If you're doing an RTAS, change these project settings (these can all be ignored if you're only doing a VST): | |||
| - Set "C++/Code Generation/Runtime Library" to be "Multi-threaded DLL" or "Multi-threaded Debug DLL" | |||
| - Set the "Linker/Input/Module Definition file" to point to "wrapper/RTAS/juce_RTAS_WinExports.def" | |||
| - Under "Linker/Input/Delay loaded DLLs", add the following: | |||
| "DAE.dll; DigiExt.dll; DSI.dll; PluginLib.dll; DSPManager.dll" | |||
| - You may (or may not) need to add "libcmtd.lib; libcmt.lib" to the "Linker/Input/Ignore Specific Library" setting. | |||
| - For ONLY the following files: | |||
| juce_RTAS_Wrapper.cpp, juce_RTAS_DigiCode1.cpp, juce_RTAS_DigiCode2.cpp, juce_RTAS_DigiCode3.cpp, | |||
| change their "C++/Advanced/Calling Convention" property to "__stdcall". All other files should | |||
| be left with the default calling convention of "__cdecl" | |||
| - Set the "Linker/General/Output File" property to "$(OutDir)\$(ProjectName).dpm" (If you're building | |||
| a polymorphic VST/RTAS, then you can simply copy or rename the finished .dpm file to a .dll, and | |||
| it'll function as a VST) | |||
| - Under "Custom build step", add the following command: | |||
| copy /Y "\yourdirectory\juce\extras\audio plugins\wrapper\RTAS\juce_RTAS_WinResources.rsr" "$(TargetPath)".rsr | |||
| The corresponding "Outputs" setting for this must be set to "$(TargetPath)".rsr | |||
| (This will copy and rename the juce_RTAS_WinResources.rsr file to sit next to the finished .dpm file. It's | |||
| a dummy resource file, but PT will refuse to load the plugin unless it has a corresponding .rsr file) | |||
| - Because the RTAS code duplicates some win32 constants, you might need to force it to link correctly | |||
| by adding "/FORCE:multiple" to the linker's additional command line options. | |||
| - You might want to change the output directory to "\Program Files\Common Files\Digidesign\DAE\Plug-Ins\" | |||
| if you want the built plugin to go directly into the PT plugins folder | |||
| - When setting properties, remember to change them for both your debug and release builds! | |||
| - Create your actual plugin classes and add them to the project. Obviously this is the hard bit! | |||
| - Add the amalgamated juce source file to the project - have a look at the demo app for neat ways of doing this. | |||
| - NOTE: on Windows, because RTAS uses the altura mac-style code, there are annoying clashes caused if | |||
| you also include the Apple QuickTime headers, so you might need to turn off quicktime by setting the | |||
| juce config macro: #define JUCE_QUICKTIME 0 | |||
| - NOTE: If you're using MSVC2005 to build your plugin, the users will need to | |||
| have the Microsoft VC8 Runtime installed on their machines, otherwise the DLL will | |||
| silently fail to load. You should probably add the runtime to your plugin's installer, | |||
| and you can get a copy of it here: | |||
| http://www.microsoft.com/downloads/details.aspx?FamilyID=32bc1bee-a3f9-4c13-9c99-220b62a191ee&DisplayLang=en | |||
| ----------------------------------------------------------------------------------------------------- | |||
| Creating a Mac AU/VST/RTAS plugin in XCode | |||
| ========================================== | |||
| - For an AU, make sure that the JucePlugin_Build_AU is enabled in your JucePluginCharacteristics.h | |||
| - In XCode, create a new project based on the "Audio Unit Effect" template | |||
| - XCode will create a bunch of template source files for you - you can remove all of these from the project | |||
| and delete them | |||
| - In the target settings, clear the "Exported Symbols File" setting. The exports are specified by directives | |||
| within the wrapper code, so don't need to be listed explicitly. | |||
| - All all the Apple frameworks that Juce normally requires to the "External Frameworks" list | |||
| - Add all the juce_AU_* files from the /wrapper/AU directory to your project | |||
| - The template project creates an AUPublic group that contains lots of AudioUnit source files. But | |||
| it leaves out files that it thinks you might not need, e.g. if you chose an "Audio Unit Effect" project, | |||
| then it won't add the classes for handling MIDI. So you'll probably need to go into this folder | |||
| and check that it contains AUMIDIBase.cpp, AUMidiEffectBase.cpp, MusicDeviceBase.cpp, etc | |||
| - As for the PC, you'll need to make sure your project contains a correctly set-up JucePluginCharacteristics.h | |||
| file - start with a copy of the one in the demo plugin project, and go through it making sure that | |||
| all the values make sense for your plugin. | |||
| - Create your actual plugin classes and add them to the project. Obviously this is the hard bit! | |||
| You should now be able to build a functional AU! If you want VST support as well, then read on... | |||
| - Make sure that the JucePlugin_Build_VST is enabled in your JucePluginCharacteristics.h | |||
| - For VST support, add all the juce_VST_* files from /wrapper/VST | |||
| - In your target info settings, add the vstsdk2_4 folder to your "Header Search Paths" list | |||
| - Make sure that in your Info.plist, the "Bundle Name" value is correctly set to the name of your plugin. | |||
| Now, if you compile, the resulting bundle should work as both a VST and AU - you can simply copy or rename it, | |||
| changing the suffix to ".vst", and put it in your VST folder. | |||
| If you also want to build an RTAS, then carry on reading... | |||
| - Make sure that the JucePlugin_Build_RTAS is enabled in your JucePluginCharacteristics.h | |||
| - After installing the Digidesign SDK, make sure you've run the config_SDK_for_Mac command in | |||
| its root directory. This sets up some of the tools that it needs. | |||
| - Add the files from /wrapper/RTAS to your project. Obviously a couple of these are for Windows, so | |||
| you shouldn't add those | |||
| - In the Digi SDK, in /AlturaPorts/TDMPlugins/common/mac, there are two config files: | |||
| CommonDebugSettings.xconfig and CommonReleaseSettings.xconfig | |||
| These contain lots of Digi hackery to get their stuff to compile, so you should add them to your project | |||
| and change your project's settings to use these files as their base config. Even so, it's all a bit of a mess, | |||
| and you may need to tweak them a bit to get it to work on your system. | |||
| - In your target settings, add a custom build setting called "MacBag", and set this to the path where the | |||
| "MacBag" folder of the Digi SDK lives. | |||
| - Add the following to your "Header Search Paths" setting (it's easiest to copy-and-paste this setting from | |||
| the demo project): | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/PlugInLibrary/**" | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/DSPManager/**" | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/SupplementalPlugInLib/Encryption" | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/SupplementalPlugInLib/GraphicsExtensions" | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/common" | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/common/PI_LibInterface" | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/PACEProtection/**" | |||
| "$(MacBag)/../AlturaPorts/OMS/Headers" | |||
| "$(MacBag)/../AlturaPorts/Fic/Interfaces/**" | |||
| "$(MacBag)/../AlturaPorts/Fic/Source/SignalNets" | |||
| "$(MacBag)/../AlturaPorts/DSIPublicInterface/PublicHeaders" | |||
| "$(MacBag)/../DAEWin/Include" | |||
| "$(MacBag)/../AlturaPorts/DigiPublic/Interfaces" | |||
| "$(MacBag)/../AlturaPorts/DigiPublic" | |||
| "$(MacBag)/../AlturaPorts/NewFileLibs/DOA" | |||
| "$(MacBag)/../AlturaPorts/NewFileLibs/Cmn" | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/SignalProcessing/**" | |||
| "$(MacBag)/../AvidCode/AVX2sdk/AVX/avx2/avx2sdk/inc" | |||
| "$(MacBag)/../AvidCode/AVX2sdk/AVX/avx2/avx2sdk/utils" | |||
| - If you get include errors compiling some of the DigiDesign code, you may need to | |||
| add "/Developer/Headers/FlatCarbon" to your header search path. | |||
| - In the SDK, find the PluginLibrary.xcodeproj file, and add this to your "External frameworks and Libraries". | |||
| If you've already compiled this library, you can open its item in your XCode project treeview, to find | |||
| the "libPluginLibrary.a" item inside it. Drag this subitem down to your Target/"Link Binary With Libraries" | |||
| build stage and drop it there to add it to the link process. | |||
| - In your Info.plist, change the "Bundle OS Type Code" to "TDMw", and the "Bundle Creator OS Type Code" to | |||
| "PTul". | |||
| - You may need to remove the "OTHER_CFLAGS = -x c++" from the RTAS settings file to stop it complaining about | |||
| obj-C code | |||
| You should now be able to build an RTAS! Again, just renaming the finished bundle to ".dpm" and | |||
| putting it in your RTAS folder should be do the trick. | |||
| If you get any weird build problems, a good tip is to try comparing the demo plugin's build settings with your | |||
| own - this should usually show up what's missing. | |||
| Note about exported symbols: | |||
| When XCode builds the plugin, I've had unpredictable results when trying to stop it from exporting | |||
| all of the internal functions as public symbols. There are some flags that are supposed to turn this | |||
| off, but sometimes they don't seem to have any effect, and using an explicit exports file also | |||
| seems a bit hit-and-miss. (If anyone knows better and can get this working, please let me know!) | |||
| Anyway, as well as being wasteful and showing everyone what's inside your plugin, leaving all | |||
| the symbols in there will cause fatal crashes when used with Tracktion, or alongside any other | |||
| Juce-based plugins. A way of making sure your plugin is stripped is to use the command | |||
| "strip -x -S YourPlugin.vst/Contents/MacOS/YourPlugin" after bulding it, which removes the | |||
| unnecessary symbols (although in my experience this also doesn't seem to work all the time, | |||
| so it's a good idea to check it using the unix "nm" command). | |||
| The Juce Polymorphic Plugin Project! | |||
| ==================================== | |||
| (c) 2008 by Raw Material Software, visit www.rawmaterialsoftware.com for more info. | |||
| ----------------------------------------------------------------------------------------------------- | |||
| The purpose of this framework is to make is simple to write an audio plugin in a generic | |||
| way, which can then be compiled as a VST, AudioUnit, RTAS, or any combination of these. | |||
| It's "polymorphic" because the output is a single binary module that acts as all of the | |||
| different plugin formats at the same time. This means that you only need to maintain one | |||
| project, and only need to perform one build to create a multi-format plugin. | |||
| Also included are some helper classes that make it easy to create a stand-alone app to | |||
| run your plugin without a host. This might be useful in its own right, but can also be very | |||
| handy when developing your plugin, because you can build, test and debug it without needing | |||
| to keep restarting a 3rd-party host. | |||
| How does it work? | |||
| ================= | |||
| To create your plugin, you just create a subclass of the AudioPluginInstance class to | |||
| perform the processing. And your plugin UI is written like any normal Juce UI component. | |||
| All the platform-specific code is hidden away in wrapper classes that you just add to | |||
| your project - you should (hopefully) never need to even see the inner workings of these. | |||
| Licensing issues | |||
| ================ | |||
| Juce is released under the GPL (Gnu Public License) - this means that you're free to use | |||
| and redistribute it as long as your products are also released under the GPL. Basically | |||
| this means that if you use it, you also have to give away your source code. | |||
| If you want to release a closed-source application, you can buy a commercial license | |||
| that lets you avoid this restriction - see http://www.rawmaterialsoftware.com/juce for more info, | |||
| or see the comments at the top of all the Juce source files. | |||
| If you're building the VST projects or releasing a VST, you'll need have a look at Steinberg's | |||
| developer site to see what licensing rules apply these days. Their website's at | |||
| http://www.steinberg.net | |||
| If you're building an RTAS then you'll need to sign Digidesign's developer license to get | |||
| their SDK. Visit http://www.digidesign.com for more info. | |||
| Getting Started | |||
| =============== | |||
| There's also a 'demo' folder - this contains an example plugin which can be built in all | |||
| the different formats. | |||
| Have a look at the demo classes to see how it works, and then to create a real plugin, | |||
| you'll need to replace the demo files with your own code. | |||
| I've tried to add helpful comments where you might run across common compile errors, to | |||
| help describe what you might be doing wrong, as getting a build set-up for some of these | |||
| formats can be a bit of a pain. Please let me know if you find there's anything missing | |||
| from these instructions or anything I could change to help smooth the build process along | |||
| a bit. | |||
| I'd recommend NOT putting your own plugin code inside the demo plugin directory - it's | |||
| much neater to keep it somewhere separate and to alter the projects to point to your | |||
| files instead of the demo ones. That way when new versions of this library come out, it'll | |||
| make it easier to update to the latest code. | |||
| ----------------------------------------------------------------------------------------------------- | |||
| Prerequisites for building a VST | |||
| ================================ | |||
| - Visit http://www.steinberg.net and jump through whatever hoops are necessary to download | |||
| and install the VST SDK. | |||
| - Make sure your include path contains an entry for the "vstsdk2.4" folder containing the SDK. | |||
| ----------------------------------------------------------------------------------------------------- | |||
| Prerequisites for building an RTAS | |||
| ================================== | |||
| - Contact Digidesign, ask to become a Digidesign Development Partner, sign the relevent | |||
| agreements and NDAs. | |||
| - From the Digidesign website, download their latest Plug-In SDK | |||
| - Install the SDK and build some of the demo plugins to make sure it all works. | |||
| - In Visual Studio: Add all of these to your include path: | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\EffectClasses | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses\Interfaces | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Utilities | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\RTASP_Adapt | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\CoreClasses | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Controls | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Meters | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ViewClasses | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\DSPClasses | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Interfaces | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\common | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\common\Platform | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\SignalProcessing\Public | |||
| C:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugIns\DSPManager\Interfaces | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\SADriver\Interfaces | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\DigiPublic\Interfaces | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\Fic\Interfaces\DAEClient | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\NewFileLibs\Cmn | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\NewFileLibs\DOA | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\AlturaSource\PPC_H | |||
| c:\yourdirectory\PT_80_SDK\AlturaPorts\AlturaSource\AppSupport | |||
| c:\yourdirectory\PT_80_SDK\AvidCode\AVX2sdk\AVX\avx2\avx2sdk\inc | |||
| C:\yourdirectory\PT_80_SDK\xplat\AVX\avx2\avx2sdk\inc | |||
| - In Visual Studio: Using the Digidesign demo projects in the SDK, make sure you've compiled | |||
| debug and release versions of the following static libraries: | |||
| DAE.lib, DigiExt.lib, DSI.lib, PlugInLib.lib. | |||
| - In XCode: After installing the Digidesign SDK, make sure you've run the config_SDK_for_Mac | |||
| command in the SDK's root directory. This sets up some of the tools that it needs. | |||
| - In XCode: If you're using the Digi files CommonDebugSettings.xcconfig and CommonReleaseSettings.xcconfig, | |||
| then you'll probably have to remove the "-x c++" option from their OTHER_CFLAGS setting, because | |||
| that prevents it compiling obj-C. Also, you might need to comment-out the GCC_PREFIX_HEADER setting, | |||
| unless you can persuade precompiled headers to work (I've never managed to get them working myself..) | |||
| You'll also probably want to add a "MacBag" setting to these files, rather than putting it into | |||
| your project - e.g. "MacBag = /Users/jules/SDKs/PT_80_SDK/MacBag" | |||
| ----------------------------------------------------------------------------------------------------- | |||
| Choosing the formats to build | |||
| ============================= | |||
| Each plugin project needs to contain a JucePluginCharacteristics.h file, which holds all the | |||
| plugin-specific build details. In here, there are three macros that you can set to enable each | |||
| of the available formats: | |||
| #define JucePlugin_Build_VST 1 | |||
| #define JucePlugin_Build_RTAS 1 | |||
| #define JucePlugin_Build_AU 1 | |||
| You can set these to 0 to disable the formats that you don't want to build, and this will avoid | |||
| any compilation problems if, for example, you don't have the appropriate SDK for a particular format. | |||
| ----------------------------------------------------------------------------------------------------- | |||
| Creating a PC VST/RTAS plugin in Visual Studio | |||
| ============================================== | |||
| - First try loading the VST demo project in JuceAudioPlugin/demo/build. Hopefully this | |||
| should build correctly. | |||
| - Create a new, empty, win32 project using Visual Studio. Choose "DLL" as the type of | |||
| product to build | |||
| - If building an RTAS, add to your project all the juce_RTAS_*.cpp files from the wrapper/RTAS folder. | |||
| - If building a VST, add to your project all the juce_VST_*.cpp files from the wrapper/VST folder. | |||
| - Create yourself a JucePluginCharacteristics.h file, starting with a copy of the one in the | |||
| demo project. Go through each item inside it carefully, and set them to the appropriate value | |||
| for your plugin. | |||
| - Under "Additional Include Directories", add the folder in which you're going to put | |||
| your JucePluginCharacteristics.h file. | |||
| - If you're doing an RTAS, change these project settings (these can all be ignored if you're only doing a VST): | |||
| - Set "C++/Code Generation/Runtime Library" to be "Multi-threaded DLL" or "Multi-threaded Debug DLL" | |||
| - Set the "Linker/Input/Module Definition file" to point to "wrapper/RTAS/juce_RTAS_WinExports.def" | |||
| - Under "Linker/Input/Delay loaded DLLs", add the following: | |||
| "DAE.dll; DigiExt.dll; DSI.dll; PluginLib.dll; DSPManager.dll" | |||
| - You may (or may not) need to add "libcmtd.lib; libcmt.lib" to the "Linker/Input/Ignore Specific Library" setting. | |||
| - For ONLY the following files: | |||
| juce_RTAS_Wrapper.cpp, juce_RTAS_DigiCode1.cpp, juce_RTAS_DigiCode2.cpp, juce_RTAS_DigiCode3.cpp, | |||
| change their "C++/Advanced/Calling Convention" property to "__stdcall". All other files should | |||
| be left with the default calling convention of "__cdecl" | |||
| - Set the "Linker/General/Output File" property to "$(OutDir)\$(ProjectName).dpm" (If you're building | |||
| a polymorphic VST/RTAS, then you can simply copy or rename the finished .dpm file to a .dll, and | |||
| it'll function as a VST) | |||
| - Under "Custom build step", add the following command: | |||
| copy /Y "\yourdirectory\juce\extras\audio plugins\wrapper\RTAS\juce_RTAS_WinResources.rsr" "$(TargetPath)".rsr | |||
| The corresponding "Outputs" setting for this must be set to "$(TargetPath)".rsr | |||
| (This will copy and rename the juce_RTAS_WinResources.rsr file to sit next to the finished .dpm file. It's | |||
| a dummy resource file, but PT will refuse to load the plugin unless it has a corresponding .rsr file) | |||
| - Because the RTAS code duplicates some win32 constants, you might need to force it to link correctly | |||
| by adding "/FORCE:multiple" to the linker's additional command line options. | |||
| - You might want to change the output directory to "\Program Files\Common Files\Digidesign\DAE\Plug-Ins\" | |||
| if you want the built plugin to go directly into the PT plugins folder | |||
| - When setting properties, remember to change them for both your debug and release builds! | |||
| - Create your actual plugin classes and add them to the project. Obviously this is the hard bit! | |||
| - Add the amalgamated juce source file to the project - have a look at the demo app for neat ways of doing this. | |||
| - NOTE: on Windows, because RTAS uses the altura mac-style code, there are annoying clashes caused if | |||
| you also include the Apple QuickTime headers, so you might need to turn off quicktime by setting the | |||
| juce config macro: #define JUCE_QUICKTIME 0 | |||
| - NOTE: If you're using MSVC2005 to build your plugin, the users will need to | |||
| have the Microsoft VC8 Runtime installed on their machines, otherwise the DLL will | |||
| silently fail to load. You should probably add the runtime to your plugin's installer, | |||
| and you can get a copy of it here: | |||
| http://www.microsoft.com/downloads/details.aspx?FamilyID=32bc1bee-a3f9-4c13-9c99-220b62a191ee&DisplayLang=en | |||
| ----------------------------------------------------------------------------------------------------- | |||
| Creating a Mac AU/VST/RTAS plugin in XCode | |||
| ========================================== | |||
| - For an AU, make sure that the JucePlugin_Build_AU is enabled in your JucePluginCharacteristics.h | |||
| - In XCode, create a new project based on the "Audio Unit Effect" template | |||
| - XCode will create a bunch of template source files for you - you can remove all of these from the project | |||
| and delete them | |||
| - In the target settings, clear the "Exported Symbols File" setting. The exports are specified by directives | |||
| within the wrapper code, so don't need to be listed explicitly. | |||
| - All all the Apple frameworks that Juce normally requires to the "External Frameworks" list | |||
| - Add all the juce_AU_* files from the /wrapper/AU directory to your project | |||
| - The template project creates an AUPublic group that contains lots of AudioUnit source files. But | |||
| it leaves out files that it thinks you might not need, e.g. if you chose an "Audio Unit Effect" project, | |||
| then it won't add the classes for handling MIDI. So you'll probably need to go into this folder | |||
| and check that it contains AUMIDIBase.cpp, AUMidiEffectBase.cpp, MusicDeviceBase.cpp, etc | |||
| - As for the PC, you'll need to make sure your project contains a correctly set-up JucePluginCharacteristics.h | |||
| file - start with a copy of the one in the demo plugin project, and go through it making sure that | |||
| all the values make sense for your plugin. | |||
| - Because of the flat naming structure used by Objective-C, if a host loads several different plugins which | |||
| all contain slightly different versions of the juce library, you can get nasty situations where all their obj-C | |||
| classes are cross-linked to the similarly-named class in other modules, and everything turns into a big mess... | |||
| To avoid this, you're advised to set a unique JUCE_ObjCExtraSuffix value (you'll find this in juce_mac_NativeCode.mm, | |||
| or if you're using the amalgamated version, you can just set it before including juce_amalgamated.cpp). Choose a | |||
| suffix that's unique to both the name and version of your plugin. | |||
| - Create your actual plugin classes and add them to the project. Obviously this is the hard bit! | |||
| You should now be able to build a functional AU! If you want VST support as well, then read on... | |||
| - Make sure that the JucePlugin_Build_VST is enabled in your JucePluginCharacteristics.h | |||
| - For VST support, add all the juce_VST_* files from /wrapper/VST | |||
| - In your target info settings, add the vstsdk2_4 folder to your "Header Search Paths" list | |||
| - Make sure that in your Info.plist, the "Bundle Name" value is correctly set to the name of your plugin. | |||
| Now, if you compile, the resulting bundle should work as both a VST and AU - you can simply copy or rename it, | |||
| changing the suffix to ".vst", and put it in your VST folder. | |||
| NOTE! If you use the Finder to rename your xyz.component file to xyz.vst, it might look like it's done | |||
| exactly this... but in fact, the Finder may have secretly renamed it as "xyz.vst.component", even though | |||
| it shows "xyz.vst" as the name on the screen. I have wasted quite a lot of time angrily wondering why my VSTs | |||
| don't seem to work, before realising that this is what has happened. You should use the command-line to rename | |||
| it correctly. | |||
| If you also want to build an RTAS, then carry on reading... | |||
| - Make sure that the JucePlugin_Build_RTAS is enabled in your JucePluginCharacteristics.h | |||
| - After installing the Digidesign SDK, make sure you've run the config_SDK_for_Mac command in | |||
| its root directory. This sets up some of the tools that it needs. | |||
| - Add the files from /wrapper/RTAS to your project. Obviously a couple of these are for Windows, so | |||
| you shouldn't add those | |||
| - In the Digi SDK, in /AlturaPorts/TDMPlugins/common/mac, there are two config files: | |||
| CommonDebugSettings.xconfig and CommonReleaseSettings.xconfig | |||
| These contain lots of Digi hackery to get their stuff to compile, so you should add them to your project | |||
| and change your project's settings to use these files as their base config. Even so, it's all a bit of a mess, | |||
| and you may need to tweak them a bit to get it to work on your system. | |||
| - In your target settings, add a custom build setting called "MacBag", and set this to the path where the | |||
| "MacBag" folder of the Digi SDK lives. | |||
| - Add the following to your "Header Search Paths" setting (it's easiest to copy-and-paste this setting from | |||
| the demo project): | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/PlugInLibrary/**" | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/DSPManager/**" | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/SupplementalPlugInLib/Encryption" | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/SupplementalPlugInLib/GraphicsExtensions" | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/common" | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/common/PI_LibInterface" | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/PACEProtection/**" | |||
| "$(MacBag)/../AlturaPorts/OMS/Headers" | |||
| "$(MacBag)/../AlturaPorts/Fic/Interfaces/**" | |||
| "$(MacBag)/../AlturaPorts/Fic/Source/SignalNets" | |||
| "$(MacBag)/../AlturaPorts/DSIPublicInterface/PublicHeaders" | |||
| "$(MacBag)/../DAEWin/Include" | |||
| "$(MacBag)/../AlturaPorts/DigiPublic/Interfaces" | |||
| "$(MacBag)/../AlturaPorts/DigiPublic" | |||
| "$(MacBag)/../AlturaPorts/NewFileLibs/DOA" | |||
| "$(MacBag)/../AlturaPorts/NewFileLibs/Cmn" | |||
| "$(MacBag)/../AlturaPorts/TDMPlugIns/SignalProcessing/**" | |||
| "$(MacBag)/../AvidCode/AVX2sdk/AVX/avx2/avx2sdk/inc" | |||
| "$(MacBag)/../AvidCode/AVX2sdk/AVX/avx2/avx2sdk/utils" | |||
| - If you get include errors compiling some of the DigiDesign code, you may need to | |||
| add "/Developer/Headers/FlatCarbon" to your header search path. | |||
| - In the SDK, find the PluginLibrary.xcodeproj file, and add this to your "External frameworks and Libraries". | |||
| If you've already compiled this library, you can open its item in your XCode project treeview, to find | |||
| the "libPluginLibrary.a" item inside it. Drag this subitem down to your Target/"Link Binary With Libraries" | |||
| build stage and drop it there to add it to the link process. | |||
| - In your Info.plist, change the "Bundle OS Type Code" to "TDMw", and the "Bundle Creator OS Type Code" to | |||
| "PTul". | |||
| - You may need to remove the "OTHER_CFLAGS = -x c++" from the RTAS settings file to stop it complaining about | |||
| obj-C code | |||
| You should now be able to build an RTAS! Again, just renaming the finished bundle to ".dpm" and | |||
| putting it in your RTAS folder should be do the trick. | |||
| If you get any weird build problems, a good tip is to try comparing the demo plugin's build settings with your | |||
| own - this should usually show up what's missing. | |||
| Note about exported symbols: | |||
| When XCode builds the plugin, I've had unpredictable results when trying to stop it from exporting | |||
| all of the internal functions as public symbols. There are some flags that are supposed to turn this | |||
| off, but sometimes they don't seem to have any effect, and using an explicit exports file also | |||
| seems a bit hit-and-miss. (If anyone knows better and can get this working, please let me know!) | |||
| Anyway, as well as being wasteful and showing everyone what's inside your plugin, leaving all | |||
| the symbols in there will cause fatal crashes when used with Tracktion, or alongside any other | |||
| Juce-based plugins. A way of making sure your plugin is stripped is to use the command | |||
| "strip -x -S YourPlugin.vst/Contents/MacOS/YourPlugin" after bulding it, which removes the | |||
| unnecessary symbols (although in my experience this also doesn't seem to work all the time, | |||
| so it's a good idea to check it using the unix "nm" command). | |||
| @@ -5,23 +5,25 @@ | |||
| <key>CFBundleDevelopmentRegion</key> | |||
| <string>English</string> | |||
| <key>CFBundleExecutable</key> | |||
| <string>${EXECUTABLE_NAME}</string> | |||
| <string>EXECUTABLE_NAME</string> | |||
| <key>CFBundleGetInfoString</key> | |||
| <string>VERSION_STR</string> | |||
| <key>CFBundleIconFile</key> | |||
| <string></string> | |||
| <key>CFBundleIdentifier</key> | |||
| <string>com.rawmaterialsoftware.${PRODUCT_NAME:identifier}</string> | |||
| <string>com.rawmaterialsoftware.PRODUCT_NAME</string> | |||
| <key>CFBundleName</key> | |||
| <string>${PRODUCT_NAME}</string> | |||
| <string>PRODUCT_NAME</string> | |||
| <key>CFBundleInfoDictionaryVersion</key> | |||
| <string>6.0</string> | |||
| <key>CFBundlePackageType</key> | |||
| <string>BNDL</string> | |||
| <string>TDMw</string> | |||
| <key>CFBundleShortVersionString</key> | |||
| <string>1.1</string> | |||
| <key>CFBundleSignature</key> | |||
| <string>????</string> | |||
| <string>PTul</string> | |||
| <key>CFBundleVersion</key> | |||
| <string>1.1</string> | |||
| <string>VERSION_NUM</string> | |||
| <key>CSResourcesFileMapped</key> | |||
| <true/> | |||
| </dict> | |||
| @@ -49,9 +49,8 @@ | |||
| 843796E00EFBFD16002A2725 /* juce_RTAS_MacResources.r in Rez */ = {isa = PBXBuildFile; fileRef = 843796D90EFBFD16002A2725 /* juce_RTAS_MacResources.r */; }; | |||
| 843796E10EFBFD16002A2725 /* juce_RTAS_MacUtilities.mm in Sources */ = {isa = PBXBuildFile; fileRef = 843796DA0EFBFD16002A2725 /* juce_RTAS_MacUtilities.mm */; }; | |||
| 843796E20EFBFD16002A2725 /* juce_RTAS_Wrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 843796DB0EFBFD16002A2725 /* juce_RTAS_Wrapper.cpp */; }; | |||
| 843796F60EFC0102002A2725 /* CommonDebugSettings.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 843796F40EFC0102002A2725 /* CommonDebugSettings.xcconfig */; }; | |||
| 843796F70EFC0102002A2725 /* CommonReleaseSettings.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 843796F50EFC0102002A2725 /* CommonReleaseSettings.xcconfig */; }; | |||
| 843797050EFC0269002A2725 /* libPluginLibrary.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 843797030EFC022E002A2725 /* libPluginLibrary.a */; }; | |||
| 849817021010B3C500297ECA /* JuceDemoPlugin.component in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8D01CCD20486CAD60068D4B7 /* JuceDemoPlugin.component */; }; | |||
| 84D3AB5F0FCC744600EA8080 /* AUCarbonViewBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D3AB5E0FCC744600EA8080 /* AUCarbonViewBase.cpp */; }; | |||
| 84D3AB630FCC749100EA8080 /* AUCarbonViewBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D3AB620FCC749100EA8080 /* AUCarbonViewBase.h */; }; | |||
| 84D3AB670FCC74B300EA8080 /* CarbonEventHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D3AB650FCC74B300EA8080 /* CarbonEventHandler.cpp */; }; | |||
| @@ -102,6 +101,19 @@ | |||
| }; | |||
| /* End PBXContainerItemProxy section */ | |||
| /* Begin PBXCopyFilesBuildPhase section */ | |||
| 849817161010B3D100297ECA /* CopyFiles */ = { | |||
| isa = PBXCopyFilesBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| dstPath = "~/Library/Audio/Plug-Ins/Components"; | |||
| dstSubfolderSpec = 0; | |||
| files = ( | |||
| 849817021010B3C500297ECA /* JuceDemoPlugin.component in CopyFiles */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| /* End PBXCopyFilesBuildPhase section */ | |||
| /* Begin PBXFileReference section */ | |||
| 089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; }; | |||
| 3EEA126B089847F5002C6BFC /* CAVectorUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CAVectorUnit.cpp; sourceTree = "<group>"; }; | |||
| @@ -500,6 +512,7 @@ | |||
| 8D01CCCB0486CAD60068D4B7 /* Sources */, | |||
| 8D01CCCD0486CAD60068D4B7 /* Frameworks */, | |||
| 8D01CCCF0486CAD60068D4B7 /* Rez */, | |||
| 849817161010B3D100297ECA /* CopyFiles */, | |||
| ); | |||
| buildRules = ( | |||
| ); | |||
| @@ -550,8 +563,6 @@ | |||
| buildActionMask = 2147483647; | |||
| files = ( | |||
| 8D01CCCA0486CAD60068D4B7 /* InfoPlist.strings in Resources */, | |||
| 843796F60EFC0102002A2725 /* CommonDebugSettings.xcconfig in Resources */, | |||
| 843796F70EFC0102002A2725 /* CommonReleaseSettings.xcconfig in Resources */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -638,6 +649,7 @@ | |||
| INFOPLIST_FILE = Info.plist; | |||
| INSTALL_PATH = "$(HOME)/Library/Audio/Plug-Ins/Components/"; | |||
| LIBRARY_STYLE = Bundle; | |||
| MACOSX_DEPLOYMENT_TARGET = 10.4; | |||
| OTHER_LDFLAGS = "-bundle"; | |||
| OTHER_REZFLAGS = "-d ppc_$ppc -d i386_$i386 -d ppc64_$ppc64 -d x86_64_$x86_64 -I /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Versions/A/Headers -I \"$(DEVELOPER_DIR)/Examples/CoreAudio/AudioUnits/AUPublic/AUBase\""; | |||
| PRODUCT_NAME = JuceDemoPlugin; | |||
| @@ -39,20 +39,22 @@ ifeq ($(CONFIG),Release) | |||
| endif | |||
| OBJECTS := \ | |||
| $(OBJDIR)/MainDemoWindow.o \ | |||
| $(OBJDIR)/BinaryData.o \ | |||
| $(OBJDIR)/ApplicationStartup.o \ | |||
| $(OBJDIR)/BinaryData.o \ | |||
| $(OBJDIR)/juce_LibrarySource.o \ | |||
| $(OBJDIR)/TreeViewDemo.o \ | |||
| $(OBJDIR)/MainDemoWindow.o \ | |||
| $(OBJDIR)/WebBrowserDemo.o \ | |||
| $(OBJDIR)/WidgetsDemo.o \ | |||
| $(OBJDIR)/DragAndDropDemo.o \ | |||
| $(OBJDIR)/FontsAndTextDemo.o \ | |||
| $(OBJDIR)/InterprocessCommsDemo.o \ | |||
| $(OBJDIR)/OpenGLDemo.o \ | |||
| $(OBJDIR)/PathsAndTransformsDemo.o \ | |||
| $(OBJDIR)/ThreadingDemo.o \ | |||
| $(OBJDIR)/TreeViewDemo.o \ | |||
| $(OBJDIR)/QuickTimeDemo.o \ | |||
| $(OBJDIR)/TableDemo.o \ | |||
| $(OBJDIR)/ThreadingDemo.o \ | |||
| $(OBJDIR)/OpenGLDemo.o \ | |||
| $(OBJDIR)/PathsAndTransformsDemo.o \ | |||
| $(OBJDIR)/FontsAndTextDemo.o \ | |||
| $(OBJDIR)/InterprocessCommsDemo.o \ | |||
| $(OBJDIR)/DragAndDropDemo.o \ | |||
| $(OBJDIR)/CameraDemo.o \ | |||
| $(OBJDIR)/AudioDemo.o \ | |||
| MKDIR_TYPE := msdos | |||
| @@ -95,7 +97,7 @@ else | |||
| -@if exist $(subst /,\,$(OBJDIR)) rmdir /s /q $(subst /,\,$(OBJDIR)) | |||
| endif | |||
| $(OBJDIR)/MainDemoWindow.o: ../../src/MainDemoWindow.cpp | |||
| $(OBJDIR)/ApplicationStartup.o: ../../src/ApplicationStartup.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| @@ -105,17 +107,17 @@ $(OBJDIR)/BinaryData.o: ../../src/BinaryData.cpp | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/ApplicationStartup.o: ../../src/ApplicationStartup.cpp | |||
| $(OBJDIR)/juce_LibrarySource.o: ../../src/juce_LibrarySource.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/juce_LibrarySource.o: ../../src/juce_LibrarySource.cpp | |||
| $(OBJDIR)/MainDemoWindow.o: ../../src/MainDemoWindow.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/TreeViewDemo.o: ../../src/demos/TreeViewDemo.cpp | |||
| $(OBJDIR)/WebBrowserDemo.o: ../../src/demos/WebBrowserDemo.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| @@ -125,17 +127,22 @@ $(OBJDIR)/WidgetsDemo.o: ../../src/demos/WidgetsDemo.cpp | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/DragAndDropDemo.o: ../../src/demos/DragAndDropDemo.cpp | |||
| $(OBJDIR)/ThreadingDemo.o: ../../src/demos/ThreadingDemo.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/FontsAndTextDemo.o: ../../src/demos/FontsAndTextDemo.cpp | |||
| $(OBJDIR)/TreeViewDemo.o: ../../src/demos/TreeViewDemo.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/InterprocessCommsDemo.o: ../../src/demos/InterprocessCommsDemo.cpp | |||
| $(OBJDIR)/QuickTimeDemo.o: ../../src/demos/QuickTimeDemo.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/TableDemo.o: ../../src/demos/TableDemo.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| @@ -150,17 +157,22 @@ $(OBJDIR)/PathsAndTransformsDemo.o: ../../src/demos/PathsAndTransformsDemo.cpp | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/QuickTimeDemo.o: ../../src/demos/QuickTimeDemo.cpp | |||
| $(OBJDIR)/FontsAndTextDemo.o: ../../src/demos/FontsAndTextDemo.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/TableDemo.o: ../../src/demos/TableDemo.cpp | |||
| $(OBJDIR)/InterprocessCommsDemo.o: ../../src/demos/InterprocessCommsDemo.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/ThreadingDemo.o: ../../src/demos/ThreadingDemo.cpp | |||
| $(OBJDIR)/DragAndDropDemo.o: ../../src/demos/DragAndDropDemo.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/CameraDemo.o: ../../src/demos/CameraDemo.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| @@ -189,7 +189,8 @@ private: | |||
| void setFile (const File& newFile) | |||
| { | |||
| setJucerComponentFile (document, component, | |||
| newFile.getRelativePathFrom (document.getFile().getParentDirectory())); | |||
| newFile.getRelativePathFrom (document.getFile().getParentDirectory()) | |||
| .replaceCharacter (T('\\'), T('/'))); | |||
| } | |||
| const File getFile() const | |||
| @@ -999,7 +999,8 @@ private: | |||
| void setFile (const File& newFile) | |||
| { | |||
| document.perform (new JucerCompFileChangeAction (component, *document.getComponentLayout(), tabIndex, | |||
| newFile.getRelativePathFrom (document.getFile().getParentDirectory())), | |||
| newFile.getRelativePathFrom (document.getFile().getParentDirectory()) | |||
| .replaceCharacter (T('\\'), T('/'))), | |||
| T("Change tab component file")); | |||
| } | |||
| @@ -302,7 +302,11 @@ void BinaryResources::fillInGeneratedCode (GeneratedCode& code) const | |||
| const MemoryBlock& mb = resources[i]->data; | |||
| defs << "// JUCER_RESOURCE: " << name << ", " << mb.getSize() | |||
| << ", \"" << File (resources[i]->originalFilename).getRelativePathFrom (code.document->getFile()) << "\"\n"; | |||
| << ", \"" | |||
| << File (resources[i]->originalFilename) | |||
| .getRelativePathFrom (code.document->getFile()) | |||
| .replaceCharacter (T('\\'), T('/')) | |||
| << "\"\n"; | |||
| String line1; | |||
| line1 << "static const unsigned char resource_" | |||
| @@ -15826,7 +15826,8 @@ bool ThreadPool::removeJob (ThreadPoolJob* const job, | |||
| } | |||
| bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, | |||
| const int timeOutMs) | |||
| const int timeOutMs, | |||
| const bool deleteInactiveJobs) | |||
| { | |||
| lock.enter(); | |||
| @@ -15842,6 +15843,9 @@ bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, | |||
| else | |||
| { | |||
| jobs.remove (i); | |||
| if (deleteInactiveJobs) | |||
| delete job; | |||
| } | |||
| } | |||
| @@ -30344,7 +30348,7 @@ bool AudioUnitPluginFormat::doesPluginStillExist (const PluginDescription& desc) | |||
| const FileSearchPath AudioUnitPluginFormat::getDefaultLocationsToSearch() | |||
| { | |||
| return FileSearchPath ("(Default AudioUnit locations)"); | |||
| return FileSearchPath ("/(Default AudioUnit locations)"); | |||
| } | |||
| #endif | |||
| @@ -96044,13 +96048,9 @@ local block_state deflate_rle(s, flush) | |||
| #endif | |||
| /********* End of inlined file: deflate.c *********/ | |||
| /********* Start of inlined file: infback.c *********/ | |||
| /* | |||
| This code is largely copied from inflate.c. Normally either infback.o or | |||
| inflate.o would be linked into an application--not both. The interface | |||
| with inffast.c is retained so that optimized assembler-coded versions of | |||
| inflate_fast() can be used with either inflate.c or infback.c. | |||
| */ | |||
| //#include "zlib/infback.c" | |||
| /********* Start of inlined file: inffast.c *********/ | |||
| /********* Start of inlined file: inftrees.h *********/ | |||
| /* WARNING: this file should *not* be used by applications. It is | |||
| @@ -96237,710 +96237,6 @@ struct inflate_state { | |||
| void inflate_fast OF((z_streamp strm, unsigned start)); | |||
| /********* End of inlined file: inffast.h *********/ | |||
| /* function prototypes */ | |||
| local void fixedtables1 OF((struct inflate_state FAR *state)); | |||
| /* | |||
| strm provides memory allocation functions in zalloc and zfree, or | |||
| Z_NULL to use the library memory allocation functions. | |||
| windowBits is in the range 8..15, and window is a user-supplied | |||
| window and output buffer that is 2**windowBits bytes. | |||
| */ | |||
| int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size) | |||
| { | |||
| struct inflate_state FAR *state; | |||
| if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || | |||
| stream_size != (int)(sizeof(z_stream))) | |||
| return Z_VERSION_ERROR; | |||
| if (strm == Z_NULL || window == Z_NULL || | |||
| windowBits < 8 || windowBits > 15) | |||
| return Z_STREAM_ERROR; | |||
| strm->msg = Z_NULL; /* in case we return an error */ | |||
| if (strm->zalloc == (alloc_func)0) { | |||
| strm->zalloc = zcalloc; | |||
| strm->opaque = (voidpf)0; | |||
| } | |||
| if (strm->zfree == (free_func)0) strm->zfree = zcfree; | |||
| state = (struct inflate_state FAR *)ZALLOC(strm, 1, | |||
| sizeof(struct inflate_state)); | |||
| if (state == Z_NULL) return Z_MEM_ERROR; | |||
| Tracev((stderr, "inflate: allocated\n")); | |||
| strm->state = (struct internal_state FAR *)state; | |||
| state->dmax = 32768U; | |||
| state->wbits = windowBits; | |||
| state->wsize = 1U << windowBits; | |||
| state->window = window; | |||
| state->write = 0; | |||
| state->whave = 0; | |||
| return Z_OK; | |||
| } | |||
| /* | |||
| Return state with length and distance decoding tables and index sizes set to | |||
| fixed code decoding. Normally this returns fixed tables from inffixed.h. | |||
| If BUILDFIXED is defined, then instead this routine builds the tables the | |||
| first time it's called, and returns those tables the first time and | |||
| thereafter. This reduces the size of the code by about 2K bytes, in | |||
| exchange for a little execution time. However, BUILDFIXED should not be | |||
| used for threaded applications, since the rewriting of the tables and virgin | |||
| may not be thread-safe. | |||
| */ | |||
| local void fixedtables1 (struct inflate_state FAR *state) | |||
| { | |||
| #ifdef BUILDFIXED | |||
| static int virgin = 1; | |||
| static code *lenfix, *distfix; | |||
| static code fixed[544]; | |||
| /* build fixed huffman tables if first call (may not be thread safe) */ | |||
| if (virgin) { | |||
| unsigned sym, bits; | |||
| static code *next; | |||
| /* literal/length table */ | |||
| sym = 0; | |||
| while (sym < 144) state->lens[sym++] = 8; | |||
| while (sym < 256) state->lens[sym++] = 9; | |||
| while (sym < 280) state->lens[sym++] = 7; | |||
| while (sym < 288) state->lens[sym++] = 8; | |||
| next = fixed; | |||
| lenfix = next; | |||
| bits = 9; | |||
| inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); | |||
| /* distance table */ | |||
| sym = 0; | |||
| while (sym < 32) state->lens[sym++] = 5; | |||
| distfix = next; | |||
| bits = 5; | |||
| inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); | |||
| /* do this just once */ | |||
| virgin = 0; | |||
| } | |||
| #else /* !BUILDFIXED */ | |||
| /********* Start of inlined file: inffixed.h *********/ | |||
| /* inffixed.h -- table for decoding fixed codes | |||
| * Generated automatically by makefixed(). | |||
| */ | |||
| /* WARNING: this file should *not* be used by applications. It | |||
| is part of the implementation of the compression library and | |||
| is subject to change. Applications should only use zlib.h. | |||
| */ | |||
| static const code lenfix[512] = { | |||
| {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, | |||
| {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, | |||
| {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, | |||
| {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, | |||
| {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, | |||
| {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, | |||
| {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, | |||
| {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, | |||
| {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, | |||
| {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, | |||
| {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, | |||
| {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, | |||
| {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, | |||
| {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, | |||
| {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, | |||
| {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, | |||
| {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, | |||
| {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, | |||
| {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, | |||
| {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, | |||
| {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, | |||
| {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, | |||
| {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, | |||
| {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, | |||
| {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, | |||
| {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, | |||
| {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, | |||
| {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, | |||
| {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, | |||
| {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, | |||
| {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, | |||
| {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, | |||
| {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, | |||
| {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, | |||
| {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, | |||
| {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, | |||
| {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, | |||
| {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, | |||
| {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, | |||
| {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, | |||
| {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, | |||
| {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, | |||
| {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, | |||
| {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, | |||
| {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, | |||
| {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, | |||
| {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, | |||
| {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, | |||
| {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, | |||
| {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, | |||
| {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, | |||
| {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, | |||
| {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, | |||
| {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, | |||
| {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, | |||
| {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, | |||
| {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, | |||
| {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, | |||
| {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, | |||
| {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, | |||
| {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, | |||
| {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, | |||
| {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, | |||
| {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, | |||
| {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, | |||
| {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, | |||
| {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, | |||
| {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, | |||
| {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, | |||
| {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, | |||
| {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, | |||
| {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, | |||
| {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, | |||
| {0,9,255} | |||
| }; | |||
| static const code distfix[32] = { | |||
| {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, | |||
| {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, | |||
| {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, | |||
| {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, | |||
| {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, | |||
| {22,5,193},{64,5,0} | |||
| }; | |||
| /********* End of inlined file: inffixed.h *********/ | |||
| #endif /* BUILDFIXED */ | |||
| state->lencode = lenfix; | |||
| state->lenbits = 9; | |||
| state->distcode = distfix; | |||
| state->distbits = 5; | |||
| } | |||
| /* Macros for inflateBack(): */ | |||
| /* Load returned state from inflate_fast() */ | |||
| #define LOAD() \ | |||
| do { \ | |||
| put = strm->next_out; \ | |||
| left = strm->avail_out; \ | |||
| next = strm->next_in; \ | |||
| have = strm->avail_in; \ | |||
| hold = state->hold; \ | |||
| bits = state->bits; \ | |||
| } while (0) | |||
| /* Set state from registers for inflate_fast() */ | |||
| #define RESTORE() \ | |||
| do { \ | |||
| strm->next_out = put; \ | |||
| strm->avail_out = left; \ | |||
| strm->next_in = next; \ | |||
| strm->avail_in = have; \ | |||
| state->hold = hold; \ | |||
| state->bits = bits; \ | |||
| } while (0) | |||
| /* Clear the input bit accumulator */ | |||
| #define INITBITS() \ | |||
| do { \ | |||
| hold = 0; \ | |||
| bits = 0; \ | |||
| } while (0) | |||
| /* Assure that some input is available. If input is requested, but denied, | |||
| then return a Z_BUF_ERROR from inflateBack(). */ | |||
| #define PULL() \ | |||
| do { \ | |||
| if (have == 0) { \ | |||
| have = in(in_desc, &next); \ | |||
| if (have == 0) { \ | |||
| next = Z_NULL; \ | |||
| ret = Z_BUF_ERROR; \ | |||
| goto inf_leave; \ | |||
| } \ | |||
| } \ | |||
| } while (0) | |||
| /* Get a byte of input into the bit accumulator, or return from inflateBack() | |||
| with an error if there is no input available. */ | |||
| #define PULLBYTE() \ | |||
| do { \ | |||
| PULL(); \ | |||
| have--; \ | |||
| hold += (unsigned long)(*next++) << bits; \ | |||
| bits += 8; \ | |||
| } while (0) | |||
| /* Assure that there are at least n bits in the bit accumulator. If there is | |||
| not enough available input to do that, then return from inflateBack() with | |||
| an error. */ | |||
| #define NEEDBITS(n) \ | |||
| do { \ | |||
| while (bits < (unsigned)(n)) \ | |||
| PULLBYTE(); \ | |||
| } while (0) | |||
| /* Return the low n bits of the bit accumulator (n < 16) */ | |||
| #define BITS(n) \ | |||
| ((unsigned)hold & ((1U << (n)) - 1)) | |||
| /* Remove n bits from the bit accumulator */ | |||
| #define DROPBITS(n) \ | |||
| do { \ | |||
| hold >>= (n); \ | |||
| bits -= (unsigned)(n); \ | |||
| } while (0) | |||
| /* Remove zero to seven bits as needed to go to a byte boundary */ | |||
| #define BYTEBITS() \ | |||
| do { \ | |||
| hold >>= bits & 7; \ | |||
| bits -= bits & 7; \ | |||
| } while (0) | |||
| /* Assure that some output space is available, by writing out the window | |||
| if it's full. If the write fails, return from inflateBack() with a | |||
| Z_BUF_ERROR. */ | |||
| #define ROOM() \ | |||
| do { \ | |||
| if (left == 0) { \ | |||
| put = state->window; \ | |||
| left = state->wsize; \ | |||
| state->whave = left; \ | |||
| if (out(out_desc, put, left)) { \ | |||
| ret = Z_BUF_ERROR; \ | |||
| goto inf_leave; \ | |||
| } \ | |||
| } \ | |||
| } while (0) | |||
| /* | |||
| strm provides the memory allocation functions and window buffer on input, | |||
| and provides information on the unused input on return. For Z_DATA_ERROR | |||
| returns, strm will also provide an error message. | |||
| in() and out() are the call-back input and output functions. When | |||
| inflateBack() needs more input, it calls in(). When inflateBack() has | |||
| filled the window with output, or when it completes with data in the | |||
| window, it calls out() to write out the data. The application must not | |||
| change the provided input until in() is called again or inflateBack() | |||
| returns. The application must not change the window/output buffer until | |||
| inflateBack() returns. | |||
| in() and out() are called with a descriptor parameter provided in the | |||
| inflateBack() call. This parameter can be a structure that provides the | |||
| information required to do the read or write, as well as accumulated | |||
| information on the input and output such as totals and check values. | |||
| in() should return zero on failure. out() should return non-zero on | |||
| failure. If either in() or out() fails, than inflateBack() returns a | |||
| Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it | |||
| was in() or out() that caused in the error. Otherwise, inflateBack() | |||
| returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format | |||
| error, or Z_MEM_ERROR if it could not allocate memory for the state. | |||
| inflateBack() can also return Z_STREAM_ERROR if the input parameters | |||
| are not correct, i.e. strm is Z_NULL or the state was not initialized. | |||
| */ | |||
| int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc) | |||
| { | |||
| struct inflate_state FAR *state; | |||
| unsigned char FAR *next; /* next input */ | |||
| unsigned char FAR *put; /* next output */ | |||
| unsigned have, left; /* available input and output */ | |||
| unsigned long hold; /* bit buffer */ | |||
| unsigned bits; /* bits in bit buffer */ | |||
| unsigned copy; /* number of stored or match bytes to copy */ | |||
| unsigned char FAR *from; /* where to copy match bytes from */ | |||
| code thisx; /* current decoding table entry */ | |||
| code last; /* parent table entry */ | |||
| unsigned len; /* length to copy for repeats, bits to drop */ | |||
| int ret; /* return code */ | |||
| static const unsigned short order[19] = /* permutation of code lengths */ | |||
| {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; | |||
| /* Check that the strm exists and that the state was initialized */ | |||
| if (strm == Z_NULL || strm->state == Z_NULL) | |||
| return Z_STREAM_ERROR; | |||
| state = (struct inflate_state FAR *)strm->state; | |||
| /* Reset the state */ | |||
| strm->msg = Z_NULL; | |||
| state->mode = TYPE; | |||
| state->last = 0; | |||
| state->whave = 0; | |||
| next = strm->next_in; | |||
| have = next != Z_NULL ? strm->avail_in : 0; | |||
| hold = 0; | |||
| bits = 0; | |||
| put = state->window; | |||
| left = state->wsize; | |||
| /* Inflate until end of block marked as last */ | |||
| for (;;) | |||
| switch (state->mode) { | |||
| case TYPE: | |||
| /* determine and dispatch block type */ | |||
| if (state->last) { | |||
| BYTEBITS(); | |||
| state->mode = DONE; | |||
| break; | |||
| } | |||
| NEEDBITS(3); | |||
| state->last = BITS(1); | |||
| DROPBITS(1); | |||
| switch (BITS(2)) { | |||
| case 0: /* stored block */ | |||
| Tracev((stderr, "inflate: stored block%s\n", | |||
| state->last ? " (last)" : "")); | |||
| state->mode = STORED; | |||
| break; | |||
| case 1: /* fixed block */ | |||
| fixedtables1(state); | |||
| Tracev((stderr, "inflate: fixed codes block%s\n", | |||
| state->last ? " (last)" : "")); | |||
| state->mode = LEN; /* decode codes */ | |||
| break; | |||
| case 2: /* dynamic block */ | |||
| Tracev((stderr, "inflate: dynamic codes block%s\n", | |||
| state->last ? " (last)" : "")); | |||
| state->mode = TABLE; | |||
| break; | |||
| case 3: | |||
| strm->msg = (char *)"invalid block type"; | |||
| state->mode = BAD; | |||
| } | |||
| DROPBITS(2); | |||
| break; | |||
| case STORED: | |||
| /* get and verify stored block length */ | |||
| BYTEBITS(); /* go to byte boundary */ | |||
| NEEDBITS(32); | |||
| if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { | |||
| strm->msg = (char *)"invalid stored block lengths"; | |||
| state->mode = BAD; | |||
| break; | |||
| } | |||
| state->length = (unsigned)hold & 0xffff; | |||
| Tracev((stderr, "inflate: stored length %u\n", | |||
| state->length)); | |||
| INITBITS(); | |||
| /* copy stored block from input to output */ | |||
| while (state->length != 0) { | |||
| copy = state->length; | |||
| PULL(); | |||
| ROOM(); | |||
| if (copy > have) copy = have; | |||
| if (copy > left) copy = left; | |||
| zmemcpy(put, next, copy); | |||
| have -= copy; | |||
| next += copy; | |||
| left -= copy; | |||
| put += copy; | |||
| state->length -= copy; | |||
| } | |||
| Tracev((stderr, "inflate: stored end\n")); | |||
| state->mode = TYPE; | |||
| break; | |||
| case TABLE: | |||
| /* get dynamic table entries descriptor */ | |||
| NEEDBITS(14); | |||
| state->nlen = BITS(5) + 257; | |||
| DROPBITS(5); | |||
| state->ndist = BITS(5) + 1; | |||
| DROPBITS(5); | |||
| state->ncode = BITS(4) + 4; | |||
| DROPBITS(4); | |||
| #ifndef PKZIP_BUG_WORKAROUND | |||
| if (state->nlen > 286 || state->ndist > 30) { | |||
| strm->msg = (char *)"too many length or distance symbols"; | |||
| state->mode = BAD; | |||
| break; | |||
| } | |||
| #endif | |||
| Tracev((stderr, "inflate: table sizes ok\n")); | |||
| /* get code length code lengths (not a typo) */ | |||
| state->have = 0; | |||
| while (state->have < state->ncode) { | |||
| NEEDBITS(3); | |||
| state->lens[order[state->have++]] = (unsigned short)BITS(3); | |||
| DROPBITS(3); | |||
| } | |||
| while (state->have < 19) | |||
| state->lens[order[state->have++]] = 0; | |||
| state->next = state->codes; | |||
| state->lencode = (code const FAR *)(state->next); | |||
| state->lenbits = 7; | |||
| ret = inflate_table(CODES, state->lens, 19, &(state->next), | |||
| &(state->lenbits), state->work); | |||
| if (ret) { | |||
| strm->msg = (char *)"invalid code lengths set"; | |||
| state->mode = BAD; | |||
| break; | |||
| } | |||
| Tracev((stderr, "inflate: code lengths ok\n")); | |||
| /* get length and distance code code lengths */ | |||
| state->have = 0; | |||
| while (state->have < state->nlen + state->ndist) { | |||
| for (;;) { | |||
| thisx = state->lencode[BITS(state->lenbits)]; | |||
| if ((unsigned)(thisx.bits) <= bits) break; | |||
| PULLBYTE(); | |||
| } | |||
| if (thisx.val < 16) { | |||
| NEEDBITS(thisx.bits); | |||
| DROPBITS(thisx.bits); | |||
| state->lens[state->have++] = thisx.val; | |||
| } | |||
| else { | |||
| if (thisx.val == 16) { | |||
| NEEDBITS(thisx.bits + 2); | |||
| DROPBITS(thisx.bits); | |||
| if (state->have == 0) { | |||
| strm->msg = (char *)"invalid bit length repeat"; | |||
| state->mode = BAD; | |||
| break; | |||
| } | |||
| len = (unsigned)(state->lens[state->have - 1]); | |||
| copy = 3 + BITS(2); | |||
| DROPBITS(2); | |||
| } | |||
| else if (thisx.val == 17) { | |||
| NEEDBITS(thisx.bits + 3); | |||
| DROPBITS(thisx.bits); | |||
| len = 0; | |||
| copy = 3 + BITS(3); | |||
| DROPBITS(3); | |||
| } | |||
| else { | |||
| NEEDBITS(thisx.bits + 7); | |||
| DROPBITS(thisx.bits); | |||
| len = 0; | |||
| copy = 11 + BITS(7); | |||
| DROPBITS(7); | |||
| } | |||
| if (state->have + copy > state->nlen + state->ndist) { | |||
| strm->msg = (char *)"invalid bit length repeat"; | |||
| state->mode = BAD; | |||
| break; | |||
| } | |||
| while (copy--) | |||
| state->lens[state->have++] = (unsigned short)len; | |||
| } | |||
| } | |||
| /* handle error breaks in while */ | |||
| if (state->mode == BAD) break; | |||
| /* build code tables */ | |||
| state->next = state->codes; | |||
| state->lencode = (code const FAR *)(state->next); | |||
| state->lenbits = 9; | |||
| ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), | |||
| &(state->lenbits), state->work); | |||
| if (ret) { | |||
| strm->msg = (char *)"invalid literal/lengths set"; | |||
| state->mode = BAD; | |||
| break; | |||
| } | |||
| state->distcode = (code const FAR *)(state->next); | |||
| state->distbits = 6; | |||
| ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, | |||
| &(state->next), &(state->distbits), state->work); | |||
| if (ret) { | |||
| strm->msg = (char *)"invalid distances set"; | |||
| state->mode = BAD; | |||
| break; | |||
| } | |||
| Tracev((stderr, "inflate: codes ok\n")); | |||
| state->mode = LEN; | |||
| case LEN: | |||
| /* use inflate_fast() if we have enough input and output */ | |||
| if (have >= 6 && left >= 258) { | |||
| RESTORE(); | |||
| if (state->whave < state->wsize) | |||
| state->whave = state->wsize - left; | |||
| inflate_fast(strm, state->wsize); | |||
| LOAD(); | |||
| break; | |||
| } | |||
| /* get a literal, length, or end-of-block code */ | |||
| for (;;) { | |||
| thisx = state->lencode[BITS(state->lenbits)]; | |||
| if ((unsigned)(thisx.bits) <= bits) break; | |||
| PULLBYTE(); | |||
| } | |||
| if (thisx.op && (thisx.op & 0xf0) == 0) { | |||
| last = thisx; | |||
| for (;;) { | |||
| thisx = state->lencode[last.val + | |||
| (BITS(last.bits + last.op) >> last.bits)]; | |||
| if ((unsigned)(last.bits + thisx.bits) <= bits) break; | |||
| PULLBYTE(); | |||
| } | |||
| DROPBITS(last.bits); | |||
| } | |||
| DROPBITS(thisx.bits); | |||
| state->length = (unsigned)thisx.val; | |||
| /* process literal */ | |||
| if (thisx.op == 0) { | |||
| Tracevv((stderr, thisx.val >= 0x20 && thisx.val < 0x7f ? | |||
| "inflate: literal '%c'\n" : | |||
| "inflate: literal 0x%02x\n", thisx.val)); | |||
| ROOM(); | |||
| *put++ = (unsigned char)(state->length); | |||
| left--; | |||
| state->mode = LEN; | |||
| break; | |||
| } | |||
| /* process end of block */ | |||
| if (thisx.op & 32) { | |||
| Tracevv((stderr, "inflate: end of block\n")); | |||
| state->mode = TYPE; | |||
| break; | |||
| } | |||
| /* invalid code */ | |||
| if (thisx.op & 64) { | |||
| strm->msg = (char *)"invalid literal/length code"; | |||
| state->mode = BAD; | |||
| break; | |||
| } | |||
| /* length code -- get extra bits, if any */ | |||
| state->extra = (unsigned)(thisx.op) & 15; | |||
| if (state->extra != 0) { | |||
| NEEDBITS(state->extra); | |||
| state->length += BITS(state->extra); | |||
| DROPBITS(state->extra); | |||
| } | |||
| Tracevv((stderr, "inflate: length %u\n", state->length)); | |||
| /* get distance code */ | |||
| for (;;) { | |||
| thisx = state->distcode[BITS(state->distbits)]; | |||
| if ((unsigned)(thisx.bits) <= bits) break; | |||
| PULLBYTE(); | |||
| } | |||
| if ((thisx.op & 0xf0) == 0) { | |||
| last = thisx; | |||
| for (;;) { | |||
| thisx = state->distcode[last.val + | |||
| (BITS(last.bits + last.op) >> last.bits)]; | |||
| if ((unsigned)(last.bits + thisx.bits) <= bits) break; | |||
| PULLBYTE(); | |||
| } | |||
| DROPBITS(last.bits); | |||
| } | |||
| DROPBITS(thisx.bits); | |||
| if (thisx.op & 64) { | |||
| strm->msg = (char *)"invalid distance code"; | |||
| state->mode = BAD; | |||
| break; | |||
| } | |||
| state->offset = (unsigned)thisx.val; | |||
| /* get distance extra bits, if any */ | |||
| state->extra = (unsigned)(thisx.op) & 15; | |||
| if (state->extra != 0) { | |||
| NEEDBITS(state->extra); | |||
| state->offset += BITS(state->extra); | |||
| DROPBITS(state->extra); | |||
| } | |||
| if (state->offset > state->wsize - (state->whave < state->wsize ? | |||
| left : 0)) { | |||
| strm->msg = (char *)"invalid distance too far back"; | |||
| state->mode = BAD; | |||
| break; | |||
| } | |||
| Tracevv((stderr, "inflate: distance %u\n", state->offset)); | |||
| /* copy match from window to output */ | |||
| do { | |||
| ROOM(); | |||
| copy = state->wsize - state->offset; | |||
| if (copy < left) { | |||
| from = put + copy; | |||
| copy = left - copy; | |||
| } | |||
| else { | |||
| from = put - state->offset; | |||
| copy = left; | |||
| } | |||
| if (copy > state->length) copy = state->length; | |||
| state->length -= copy; | |||
| left -= copy; | |||
| do { | |||
| *put++ = *from++; | |||
| } while (--copy); | |||
| } while (state->length != 0); | |||
| break; | |||
| case DONE: | |||
| /* inflate stream terminated properly -- write leftover output */ | |||
| ret = Z_STREAM_END; | |||
| if (left < state->wsize) { | |||
| if (out(out_desc, state->window, state->wsize - left)) | |||
| ret = Z_BUF_ERROR; | |||
| } | |||
| goto inf_leave; | |||
| case BAD: | |||
| ret = Z_DATA_ERROR; | |||
| goto inf_leave; | |||
| default: /* can't happen, but makes compilers happy */ | |||
| ret = Z_STREAM_ERROR; | |||
| goto inf_leave; | |||
| } | |||
| /* Return unused input */ | |||
| inf_leave: | |||
| strm->next_in = next; | |||
| strm->avail_in = have; | |||
| return ret; | |||
| } | |||
| int ZEXPORT inflateBackEnd (z_streamp strm) | |||
| { | |||
| if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) | |||
| return Z_STREAM_ERROR; | |||
| ZFREE(strm, strm->state); | |||
| strm->state = Z_NULL; | |||
| Tracev((stderr, "inflate: end\n")); | |||
| return Z_OK; | |||
| } | |||
| /********* End of inlined file: infback.c *********/ | |||
| /********* Start of inlined file: inffast.c *********/ | |||
| /********* Start of inlined file: inffast.h *********/ | |||
| /* WARNING: this file should *not* be used by applications. It is | |||
| part of the implementation of the compression library and is | |||
| subject to change. Applications should only use zlib.h. | |||
| */ | |||
| void inflate_fast OF((z_streamp strm, unsigned start)); | |||
| /********* End of inlined file: inffast.h *********/ | |||
| #ifndef ASMINF | |||
| /* Allow machine dependent optimization for post-increment or pre-increment. | |||
| @@ -100332,62 +99628,7 @@ local void copy_block(deflate_state *s, | |||
| } | |||
| /********* End of inlined file: trees.c *********/ | |||
| /********* Start of inlined file: uncompr.c *********/ | |||
| /* @(#) $Id: uncompr.c,v 1.1 2007/06/07 17:54:37 jules_rms Exp $ */ | |||
| #define ZLIB_INTERNAL | |||
| /* =========================================================================== | |||
| Decompresses the source buffer into the destination buffer. sourceLen is | |||
| the byte length of the source buffer. Upon entry, destLen is the total | |||
| size of the destination buffer, which must be large enough to hold the | |||
| entire uncompressed data. (The size of the uncompressed data must have | |||
| been saved previously by the compressor and transmitted to the decompressor | |||
| by some mechanism outside the scope of this compression library.) | |||
| Upon exit, destLen is the actual size of the compressed buffer. | |||
| This function can be used to decompress a whole file at once if the | |||
| input file is mmap'ed. | |||
| uncompress returns Z_OK if success, Z_MEM_ERROR if there was not | |||
| enough memory, Z_BUF_ERROR if there was not enough room in the output | |||
| buffer, or Z_DATA_ERROR if the input data was corrupted. | |||
| */ | |||
| int ZEXPORT uncompress (Bytef *dest, | |||
| uLongf *destLen, | |||
| const Bytef *source, | |||
| uLong sourceLen) | |||
| { | |||
| z_stream stream; | |||
| int err; | |||
| stream.next_in = (Bytef*)source; | |||
| stream.avail_in = (uInt)sourceLen; | |||
| /* Check for source > 64K on 16-bit machine: */ | |||
| if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; | |||
| stream.next_out = dest; | |||
| stream.avail_out = (uInt)*destLen; | |||
| if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; | |||
| stream.zalloc = (alloc_func)0; | |||
| stream.zfree = (free_func)0; | |||
| err = inflateInit(&stream); | |||
| if (err != Z_OK) return err; | |||
| err = inflate(&stream, Z_FINISH); | |||
| if (err != Z_STREAM_END) { | |||
| inflateEnd(&stream); | |||
| if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) | |||
| return Z_DATA_ERROR; | |||
| return err; | |||
| } | |||
| *destLen = stream.total_out; | |||
| err = inflateEnd(&stream); | |||
| return err; | |||
| } | |||
| /********* End of inlined file: uncompr.c *********/ | |||
| //#include "zlib/uncompr.c" | |||
| /********* Start of inlined file: zutil.c *********/ | |||
| /* @(#) $Id: zutil.c,v 1.1 2007/06/07 17:54:37 jules_rms Exp $ */ | |||
| @@ -262226,7 +261467,8 @@ public: | |||
| snd_seq_ev_set_subs (&event); | |||
| snd_seq_ev_set_direct (&event); | |||
| snd_seq_event_output_direct (seqHandle, &event); | |||
| snd_seq_event_output (seqHandle, &event); | |||
| snd_seq_drain_output (seqHandle); | |||
| } | |||
| juce_UseDebuggingNewOperator | |||
| @@ -266089,9 +265331,23 @@ BEGIN_JUCE_NAMESPACE | |||
| #undef Point | |||
| /** This suffix is used for naming all Obj-C classes that are used inside juce. | |||
| Because of the flat naming structure used by Obj-C, you can get horrible situations where | |||
| two DLLs are loaded into a host, each of which uses classes with the same names, and these get | |||
| cross-linked so that when you make a call to a class that you thought was private, it ends up | |||
| actually calling into a similarly named class in the other module's address space. | |||
| By changing this macro to a unique value, you ensure that all the obj-C classes in your app | |||
| have unique names, and should avoid this problem. | |||
| If you're using the amalgamated version, you can just set this macro to something unique before | |||
| you include juce_amalgamated.cpp. | |||
| */ | |||
| #ifndef JUCE_ObjCExtraSuffix | |||
| #define JUCE_ObjCExtraSuffix 2 | |||
| #define JUCE_ObjCExtraSuffix 3 | |||
| #endif | |||
| #define appendMacro1(a, b, c, d) a ## _ ## b ## _ ## c ## _ ## d | |||
| #define appendMacro2(a, b, c, d) appendMacro1(a, b, c, d) | |||
| #define MakeObjCClassName(rootName) appendMacro2 (rootName, JUCE_MAJOR_VERSION, JUCE_MINOR_VERSION, JUCE_ObjCExtraSuffix) | |||
| @@ -270072,16 +269328,16 @@ class NSViewComponentInternal : public ComponentMovementWatcher | |||
| bool wasShowing; | |||
| public: | |||
| NSView* view; | |||
| NSView* const view; | |||
| NSViewComponentInternal (NSView* view_, Component* const owner_) | |||
| NSViewComponentInternal (NSView* const view_, Component* const owner_) | |||
| : ComponentMovementWatcher (owner_), | |||
| owner (owner_), | |||
| currentPeer (0), | |||
| wasShowing (false), | |||
| view (view_) | |||
| { | |||
| [view retain]; | |||
| [view_ retain]; | |||
| if (owner_->isShowing()) | |||
| componentPeerChanged(); | |||
| @@ -270093,6 +269349,18 @@ public: | |||
| [view release]; | |||
| } | |||
| void componentMovedOrResized (Component& comp, bool wasMoved, bool wasResized) | |||
| { | |||
| ComponentMovementWatcher::componentMovedOrResized (comp, wasMoved, wasResized); | |||
| // The ComponentMovementWatcher version of this method avoids calling | |||
| // us when the top-level comp is resized, but for an NSView we need to know this | |||
| // because with inverted co-ords, we need to update the position even if the | |||
| // top-left pos hasn't changed | |||
| if (comp.isOnDesktop() && wasResized) | |||
| componentMovedOrResized (wasMoved, wasResized); | |||
| } | |||
| void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) | |||
| { | |||
| Component* const topComp = owner->getTopLevelComponent(); | |||
| @@ -66,7 +66,7 @@ | |||
| See also SystemStats::getJUCEVersion() for a string version. | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 46 | |||
| #define JUCE_MINOR_VERSION 50 | |||
| /** Current Juce version number. | |||
| @@ -10115,6 +10115,26 @@ public: | |||
| lock.exit(); | |||
| } | |||
| /** Inserts or replaces an object in the array, assuming it is sorted. | |||
| This is similar to addSorted, but if a matching element already exists, then it will be | |||
| replaced by the new one, rather than the new one being added as well. | |||
| */ | |||
| template <class ElementComparator> | |||
| void addOrReplaceSorted (ElementComparator& comparator, | |||
| ObjectClass* newObject) throw() | |||
| { | |||
| lock.enter(); | |||
| const int index = findInsertIndexInSortedArray (comparator, this->elements, newObject, 0, numUsed); | |||
| if (index > 0 && comparator.compareElements (newObject, this->elements [index - 1]) == 0) | |||
| set (index - 1, newObject); // replace an existing object that matches | |||
| else | |||
| insert (index, newObject); // no match, so insert the new one | |||
| lock.exit(); | |||
| } | |||
| /** Removes an object from the array. | |||
| This will remove the object at a given index and move back all the | |||
| @@ -15095,11 +15115,16 @@ public: | |||
| methods called to try to interrupt them | |||
| @param timeOutMilliseconds the length of time this method should wait for all the jobs to finish | |||
| before giving up and returning false | |||
| @param deleteInactiveJobs if true, any jobs that aren't currently running will be deleted. If false, | |||
| they will simply be removed from the pool. Jobs that are already running when | |||
| this method is called can choose whether they should be deleted by | |||
| returning jobHasFinishedAndShouldBeDeleted from their runJob() method. | |||
| @returns true if all jobs are successfully stopped and removed; false if the timeout period | |||
| expires while waiting for them to stop | |||
| */ | |||
| bool removeAllJobs (const bool interruptRunningJobs, | |||
| const int timeOutMilliseconds); | |||
| const int timeOutMilliseconds, | |||
| const bool deleteInactiveJobs = false); | |||
| /** Returns the number of jobs currently running or queued. | |||
| */ | |||
| @@ -1535,7 +1535,7 @@ bool AudioUnitPluginFormat::doesPluginStillExist (const PluginDescription& desc) | |||
| const FileSearchPath AudioUnitPluginFormat::getDefaultLocationsToSearch() | |||
| { | |||
| return FileSearchPath ("(Default AudioUnit locations)"); | |||
| return FileSearchPath ("/(Default AudioUnit locations)"); | |||
| } | |||
| #endif | |||
| @@ -38,7 +38,7 @@ | |||
| See also SystemStats::getJUCEVersion() for a string version. | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 46 | |||
| #define JUCE_MINOR_VERSION 50 | |||
| /** Current Juce version number. | |||
| @@ -442,6 +442,26 @@ public: | |||
| lock.exit(); | |||
| } | |||
| /** Inserts or replaces an object in the array, assuming it is sorted. | |||
| This is similar to addSorted, but if a matching element already exists, then it will be | |||
| replaced by the new one, rather than the new one being added as well. | |||
| */ | |||
| template <class ElementComparator> | |||
| void addOrReplaceSorted (ElementComparator& comparator, | |||
| ObjectClass* newObject) throw() | |||
| { | |||
| lock.enter(); | |||
| const int index = findInsertIndexInSortedArray (comparator, this->elements, newObject, 0, numUsed); | |||
| if (index > 0 && comparator.compareElements (newObject, this->elements [index - 1]) == 0) | |||
| set (index - 1, newObject); // replace an existing object that matches | |||
| else | |||
| insert (index, newObject); // no match, so insert the new one | |||
| lock.exit(); | |||
| } | |||
| //============================================================================== | |||
| /** Removes an object from the array. | |||
| @@ -46,14 +46,13 @@ namespace zlibNamespace | |||
| #define ZLIB_INTERNAL | |||
| #define NO_DUMMY_DECL | |||
| #include "zlib/zlib.h" | |||
| #include "zlib/adler32.c" | |||
| #include "zlib/compress.c" | |||
| #undef DO1 | |||
| #undef DO8 | |||
| #include "zlib/crc32.c" | |||
| #include "zlib/deflate.c" | |||
| #include "zlib/infback.c" | |||
| //#include "zlib/infback.c" | |||
| #include "zlib/inffast.c" | |||
| #undef PULLBYTE | |||
| #undef LOAD | |||
| @@ -65,7 +64,7 @@ namespace zlibNamespace | |||
| #include "zlib/inflate.c" | |||
| #include "zlib/inftrees.c" | |||
| #include "zlib/trees.c" | |||
| #include "zlib/uncompr.c" | |||
| //#include "zlib/uncompr.c" | |||
| #include "zlib/zutil.c" | |||
| #undef Byte | |||
| } | |||
| @@ -264,7 +264,8 @@ bool ThreadPool::removeJob (ThreadPoolJob* const job, | |||
| } | |||
| bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, | |||
| const int timeOutMs) | |||
| const int timeOutMs, | |||
| const bool deleteInactiveJobs) | |||
| { | |||
| lock.enter(); | |||
| @@ -280,6 +281,9 @@ bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, | |||
| else | |||
| { | |||
| jobs.remove (i); | |||
| if (deleteInactiveJobs) | |||
| delete job; | |||
| } | |||
| } | |||
| @@ -218,11 +218,16 @@ public: | |||
| methods called to try to interrupt them | |||
| @param timeOutMilliseconds the length of time this method should wait for all the jobs to finish | |||
| before giving up and returning false | |||
| @param deleteInactiveJobs if true, any jobs that aren't currently running will be deleted. If false, | |||
| they will simply be removed from the pool. Jobs that are already running when | |||
| this method is called can choose whether they should be deleted by | |||
| returning jobHasFinishedAndShouldBeDeleted from their runJob() method. | |||
| @returns true if all jobs are successfully stopped and removed; false if the timeout period | |||
| expires while waiting for them to stop | |||
| */ | |||
| bool removeAllJobs (const bool interruptRunningJobs, | |||
| const int timeOutMilliseconds); | |||
| const int timeOutMilliseconds, | |||
| const bool deleteInactiveJobs = false); | |||
| /** Returns the number of jobs currently running or queued. | |||
| */ | |||