| @@ -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 | #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 | #ifndef JUCE_ObjCExtraSuffix | ||||
| #define JUCE_ObjCExtraSuffix 2 | |||||
| #define JUCE_ObjCExtraSuffix 3 | |||||
| #endif | #endif | ||||
| #define appendMacro1(a, b, c, d) a ## _ ## b ## _ ## c ## _ ## d | #define appendMacro1(a, b, c, d) a ## _ ## b ## _ ## c ## _ ## d | ||||
| #define appendMacro2(a, b, c, d) appendMacro1(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) | #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> | <key>CFBundleDevelopmentRegion</key> | ||||
| <string>English</string> | <string>English</string> | ||||
| <key>CFBundleExecutable</key> | <key>CFBundleExecutable</key> | ||||
| <string>${EXECUTABLE_NAME}</string> | |||||
| <string>EXECUTABLE_NAME</string> | |||||
| <key>CFBundleGetInfoString</key> | |||||
| <string>VERSION_STR</string> | |||||
| <key>CFBundleIconFile</key> | <key>CFBundleIconFile</key> | ||||
| <string></string> | <string></string> | ||||
| <key>CFBundleIdentifier</key> | <key>CFBundleIdentifier</key> | ||||
| <string>com.rawmaterialsoftware.${PRODUCT_NAME:identifier}</string> | |||||
| <string>com.rawmaterialsoftware.PRODUCT_NAME</string> | |||||
| <key>CFBundleName</key> | <key>CFBundleName</key> | ||||
| <string>${PRODUCT_NAME}</string> | |||||
| <string>PRODUCT_NAME</string> | |||||
| <key>CFBundleInfoDictionaryVersion</key> | <key>CFBundleInfoDictionaryVersion</key> | ||||
| <string>6.0</string> | <string>6.0</string> | ||||
| <key>CFBundlePackageType</key> | <key>CFBundlePackageType</key> | ||||
| <string>BNDL</string> | |||||
| <string>TDMw</string> | |||||
| <key>CFBundleShortVersionString</key> | <key>CFBundleShortVersionString</key> | ||||
| <string>1.1</string> | <string>1.1</string> | ||||
| <key>CFBundleSignature</key> | <key>CFBundleSignature</key> | ||||
| <string>????</string> | |||||
| <string>PTul</string> | |||||
| <key>CFBundleVersion</key> | <key>CFBundleVersion</key> | ||||
| <string>1.1</string> | |||||
| <string>VERSION_NUM</string> | |||||
| <key>CSResourcesFileMapped</key> | <key>CSResourcesFileMapped</key> | ||||
| <true/> | <true/> | ||||
| </dict> | </dict> | ||||
| @@ -49,9 +49,8 @@ | |||||
| 843796E00EFBFD16002A2725 /* juce_RTAS_MacResources.r in Rez */ = {isa = PBXBuildFile; fileRef = 843796D90EFBFD16002A2725 /* juce_RTAS_MacResources.r */; }; | 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 */; }; | 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 */; }; | 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 */; }; | 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 */; }; | 84D3AB5F0FCC744600EA8080 /* AUCarbonViewBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D3AB5E0FCC744600EA8080 /* AUCarbonViewBase.cpp */; }; | ||||
| 84D3AB630FCC749100EA8080 /* AUCarbonViewBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D3AB620FCC749100EA8080 /* AUCarbonViewBase.h */; }; | 84D3AB630FCC749100EA8080 /* AUCarbonViewBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D3AB620FCC749100EA8080 /* AUCarbonViewBase.h */; }; | ||||
| 84D3AB670FCC74B300EA8080 /* CarbonEventHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D3AB650FCC74B300EA8080 /* CarbonEventHandler.cpp */; }; | 84D3AB670FCC74B300EA8080 /* CarbonEventHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D3AB650FCC74B300EA8080 /* CarbonEventHandler.cpp */; }; | ||||
| @@ -102,6 +101,19 @@ | |||||
| }; | }; | ||||
| /* End PBXContainerItemProxy section */ | /* 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 */ | /* Begin PBXFileReference section */ | ||||
| 089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; }; | 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>"; }; | 3EEA126B089847F5002C6BFC /* CAVectorUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CAVectorUnit.cpp; sourceTree = "<group>"; }; | ||||
| @@ -500,6 +512,7 @@ | |||||
| 8D01CCCB0486CAD60068D4B7 /* Sources */, | 8D01CCCB0486CAD60068D4B7 /* Sources */, | ||||
| 8D01CCCD0486CAD60068D4B7 /* Frameworks */, | 8D01CCCD0486CAD60068D4B7 /* Frameworks */, | ||||
| 8D01CCCF0486CAD60068D4B7 /* Rez */, | 8D01CCCF0486CAD60068D4B7 /* Rez */, | ||||
| 849817161010B3D100297ECA /* CopyFiles */, | |||||
| ); | ); | ||||
| buildRules = ( | buildRules = ( | ||||
| ); | ); | ||||
| @@ -550,8 +563,6 @@ | |||||
| buildActionMask = 2147483647; | buildActionMask = 2147483647; | ||||
| files = ( | files = ( | ||||
| 8D01CCCA0486CAD60068D4B7 /* InfoPlist.strings in Resources */, | 8D01CCCA0486CAD60068D4B7 /* InfoPlist.strings in Resources */, | ||||
| 843796F60EFC0102002A2725 /* CommonDebugSettings.xcconfig in Resources */, | |||||
| 843796F70EFC0102002A2725 /* CommonReleaseSettings.xcconfig in Resources */, | |||||
| ); | ); | ||||
| runOnlyForDeploymentPostprocessing = 0; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -638,6 +649,7 @@ | |||||
| INFOPLIST_FILE = Info.plist; | INFOPLIST_FILE = Info.plist; | ||||
| INSTALL_PATH = "$(HOME)/Library/Audio/Plug-Ins/Components/"; | INSTALL_PATH = "$(HOME)/Library/Audio/Plug-Ins/Components/"; | ||||
| LIBRARY_STYLE = Bundle; | LIBRARY_STYLE = Bundle; | ||||
| MACOSX_DEPLOYMENT_TARGET = 10.4; | |||||
| OTHER_LDFLAGS = "-bundle"; | 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\""; | 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; | PRODUCT_NAME = JuceDemoPlugin; | ||||
| @@ -39,20 +39,22 @@ ifeq ($(CONFIG),Release) | |||||
| endif | endif | ||||
| OBJECTS := \ | OBJECTS := \ | ||||
| $(OBJDIR)/MainDemoWindow.o \ | |||||
| $(OBJDIR)/BinaryData.o \ | |||||
| $(OBJDIR)/ApplicationStartup.o \ | $(OBJDIR)/ApplicationStartup.o \ | ||||
| $(OBJDIR)/BinaryData.o \ | |||||
| $(OBJDIR)/juce_LibrarySource.o \ | $(OBJDIR)/juce_LibrarySource.o \ | ||||
| $(OBJDIR)/TreeViewDemo.o \ | |||||
| $(OBJDIR)/MainDemoWindow.o \ | |||||
| $(OBJDIR)/WebBrowserDemo.o \ | |||||
| $(OBJDIR)/WidgetsDemo.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)/QuickTimeDemo.o \ | ||||
| $(OBJDIR)/TableDemo.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 \ | $(OBJDIR)/AudioDemo.o \ | ||||
| MKDIR_TYPE := msdos | MKDIR_TYPE := msdos | ||||
| @@ -95,7 +97,7 @@ else | |||||
| -@if exist $(subst /,\,$(OBJDIR)) rmdir /s /q $(subst /,\,$(OBJDIR)) | -@if exist $(subst /,\,$(OBJDIR)) rmdir /s /q $(subst /,\,$(OBJDIR)) | ||||
| endif | endif | ||||
| $(OBJDIR)/MainDemoWindow.o: ../../src/MainDemoWindow.cpp | |||||
| $(OBJDIR)/ApplicationStartup.o: ../../src/ApplicationStartup.cpp | |||||
| -@$(CMD_MKOBJDIR) | -@$(CMD_MKOBJDIR) | ||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | ||||
| @@ -105,17 +107,17 @@ $(OBJDIR)/BinaryData.o: ../../src/BinaryData.cpp | |||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | ||||
| $(OBJDIR)/ApplicationStartup.o: ../../src/ApplicationStartup.cpp | |||||
| $(OBJDIR)/juce_LibrarySource.o: ../../src/juce_LibrarySource.cpp | |||||
| -@$(CMD_MKOBJDIR) | -@$(CMD_MKOBJDIR) | ||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | ||||
| $(OBJDIR)/juce_LibrarySource.o: ../../src/juce_LibrarySource.cpp | |||||
| $(OBJDIR)/MainDemoWindow.o: ../../src/MainDemoWindow.cpp | |||||
| -@$(CMD_MKOBJDIR) | -@$(CMD_MKOBJDIR) | ||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | ||||
| $(OBJDIR)/TreeViewDemo.o: ../../src/demos/TreeViewDemo.cpp | |||||
| $(OBJDIR)/WebBrowserDemo.o: ../../src/demos/WebBrowserDemo.cpp | |||||
| -@$(CMD_MKOBJDIR) | -@$(CMD_MKOBJDIR) | ||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | ||||
| @@ -125,17 +127,22 @@ $(OBJDIR)/WidgetsDemo.o: ../../src/demos/WidgetsDemo.cpp | |||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | ||||
| $(OBJDIR)/DragAndDropDemo.o: ../../src/demos/DragAndDropDemo.cpp | |||||
| $(OBJDIR)/ThreadingDemo.o: ../../src/demos/ThreadingDemo.cpp | |||||
| -@$(CMD_MKOBJDIR) | -@$(CMD_MKOBJDIR) | ||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | ||||
| $(OBJDIR)/FontsAndTextDemo.o: ../../src/demos/FontsAndTextDemo.cpp | |||||
| $(OBJDIR)/TreeViewDemo.o: ../../src/demos/TreeViewDemo.cpp | |||||
| -@$(CMD_MKOBJDIR) | -@$(CMD_MKOBJDIR) | ||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | @$(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) | -@$(CMD_MKOBJDIR) | ||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | ||||
| @@ -150,17 +157,22 @@ $(OBJDIR)/PathsAndTransformsDemo.o: ../../src/demos/PathsAndTransformsDemo.cpp | |||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | ||||
| $(OBJDIR)/QuickTimeDemo.o: ../../src/demos/QuickTimeDemo.cpp | |||||
| $(OBJDIR)/FontsAndTextDemo.o: ../../src/demos/FontsAndTextDemo.cpp | |||||
| -@$(CMD_MKOBJDIR) | -@$(CMD_MKOBJDIR) | ||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | ||||
| $(OBJDIR)/TableDemo.o: ../../src/demos/TableDemo.cpp | |||||
| $(OBJDIR)/InterprocessCommsDemo.o: ../../src/demos/InterprocessCommsDemo.cpp | |||||
| -@$(CMD_MKOBJDIR) | -@$(CMD_MKOBJDIR) | ||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | @$(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) | -@$(CMD_MKOBJDIR) | ||||
| @echo $(notdir $<) | @echo $(notdir $<) | ||||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | ||||
| @@ -189,7 +189,8 @@ private: | |||||
| void setFile (const File& newFile) | void setFile (const File& newFile) | ||||
| { | { | ||||
| setJucerComponentFile (document, component, | setJucerComponentFile (document, component, | ||||
| newFile.getRelativePathFrom (document.getFile().getParentDirectory())); | |||||
| newFile.getRelativePathFrom (document.getFile().getParentDirectory()) | |||||
| .replaceCharacter (T('\\'), T('/'))); | |||||
| } | } | ||||
| const File getFile() const | const File getFile() const | ||||
| @@ -999,7 +999,8 @@ private: | |||||
| void setFile (const File& newFile) | void setFile (const File& newFile) | ||||
| { | { | ||||
| document.perform (new JucerCompFileChangeAction (component, *document.getComponentLayout(), tabIndex, | 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")); | T("Change tab component file")); | ||||
| } | } | ||||
| @@ -302,7 +302,11 @@ void BinaryResources::fillInGeneratedCode (GeneratedCode& code) const | |||||
| const MemoryBlock& mb = resources[i]->data; | const MemoryBlock& mb = resources[i]->data; | ||||
| defs << "// JUCER_RESOURCE: " << name << ", " << mb.getSize() | 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; | String line1; | ||||
| line1 << "static const unsigned char resource_" | line1 << "static const unsigned char resource_" | ||||
| @@ -15826,7 +15826,8 @@ bool ThreadPool::removeJob (ThreadPoolJob* const job, | |||||
| } | } | ||||
| bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, | bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, | ||||
| const int timeOutMs) | |||||
| const int timeOutMs, | |||||
| const bool deleteInactiveJobs) | |||||
| { | { | ||||
| lock.enter(); | lock.enter(); | ||||
| @@ -15842,6 +15843,9 @@ bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, | |||||
| else | else | ||||
| { | { | ||||
| jobs.remove (i); | jobs.remove (i); | ||||
| if (deleteInactiveJobs) | |||||
| delete job; | |||||
| } | } | ||||
| } | } | ||||
| @@ -30344,7 +30348,7 @@ bool AudioUnitPluginFormat::doesPluginStillExist (const PluginDescription& desc) | |||||
| const FileSearchPath AudioUnitPluginFormat::getDefaultLocationsToSearch() | const FileSearchPath AudioUnitPluginFormat::getDefaultLocationsToSearch() | ||||
| { | { | ||||
| return FileSearchPath ("(Default AudioUnit locations)"); | |||||
| return FileSearchPath ("/(Default AudioUnit locations)"); | |||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -96044,13 +96048,9 @@ local block_state deflate_rle(s, flush) | |||||
| #endif | #endif | ||||
| /********* End of inlined file: deflate.c *********/ | /********* 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 *********/ | /********* Start of inlined file: inftrees.h *********/ | ||||
| /* WARNING: this file should *not* be used by applications. It is | /* 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)); | void inflate_fast OF((z_streamp strm, unsigned start)); | ||||
| /********* End of inlined file: inffast.h *********/ | /********* 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 | #ifndef ASMINF | ||||
| /* Allow machine dependent optimization for post-increment or pre-increment. | /* 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 *********/ | /********* 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 *********/ | /********* Start of inlined file: zutil.c *********/ | ||||
| /* @(#) $Id: zutil.c,v 1.1 2007/06/07 17:54:37 jules_rms Exp $ */ | /* @(#) $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_subs (&event); | ||||
| snd_seq_ev_set_direct (&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 | juce_UseDebuggingNewOperator | ||||
| @@ -266089,9 +265331,23 @@ BEGIN_JUCE_NAMESPACE | |||||
| #undef Point | #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 | #ifndef JUCE_ObjCExtraSuffix | ||||
| #define JUCE_ObjCExtraSuffix 2 | |||||
| #define JUCE_ObjCExtraSuffix 3 | |||||
| #endif | #endif | ||||
| #define appendMacro1(a, b, c, d) a ## _ ## b ## _ ## c ## _ ## d | #define appendMacro1(a, b, c, d) a ## _ ## b ## _ ## c ## _ ## d | ||||
| #define appendMacro2(a, b, c, d) appendMacro1(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) | #define MakeObjCClassName(rootName) appendMacro2 (rootName, JUCE_MAJOR_VERSION, JUCE_MINOR_VERSION, JUCE_ObjCExtraSuffix) | ||||
| @@ -270072,16 +269328,16 @@ class NSViewComponentInternal : public ComponentMovementWatcher | |||||
| bool wasShowing; | bool wasShowing; | ||||
| public: | public: | ||||
| NSView* view; | |||||
| NSView* const view; | |||||
| NSViewComponentInternal (NSView* view_, Component* const owner_) | |||||
| NSViewComponentInternal (NSView* const view_, Component* const owner_) | |||||
| : ComponentMovementWatcher (owner_), | : ComponentMovementWatcher (owner_), | ||||
| owner (owner_), | owner (owner_), | ||||
| currentPeer (0), | currentPeer (0), | ||||
| wasShowing (false), | wasShowing (false), | ||||
| view (view_) | view (view_) | ||||
| { | { | ||||
| [view retain]; | |||||
| [view_ retain]; | |||||
| if (owner_->isShowing()) | if (owner_->isShowing()) | ||||
| componentPeerChanged(); | componentPeerChanged(); | ||||
| @@ -270093,6 +269349,18 @@ public: | |||||
| [view release]; | [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*/) | void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) | ||||
| { | { | ||||
| Component* const topComp = owner->getTopLevelComponent(); | Component* const topComp = owner->getTopLevelComponent(); | ||||
| @@ -66,7 +66,7 @@ | |||||
| See also SystemStats::getJUCEVersion() for a string version. | See also SystemStats::getJUCEVersion() for a string version. | ||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 46 | |||||
| #define JUCE_MINOR_VERSION 50 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -10115,6 +10115,26 @@ public: | |||||
| lock.exit(); | 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. | /** Removes an object from the array. | ||||
| This will remove the object at a given index and move back all the | 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 | methods called to try to interrupt them | ||||
| @param timeOutMilliseconds the length of time this method should wait for all the jobs to finish | @param timeOutMilliseconds the length of time this method should wait for all the jobs to finish | ||||
| before giving up and returning false | 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 | @returns true if all jobs are successfully stopped and removed; false if the timeout period | ||||
| expires while waiting for them to stop | expires while waiting for them to stop | ||||
| */ | */ | ||||
| bool removeAllJobs (const bool interruptRunningJobs, | bool removeAllJobs (const bool interruptRunningJobs, | ||||
| const int timeOutMilliseconds); | |||||
| const int timeOutMilliseconds, | |||||
| const bool deleteInactiveJobs = false); | |||||
| /** Returns the number of jobs currently running or queued. | /** Returns the number of jobs currently running or queued. | ||||
| */ | */ | ||||
| @@ -1535,7 +1535,7 @@ bool AudioUnitPluginFormat::doesPluginStillExist (const PluginDescription& desc) | |||||
| const FileSearchPath AudioUnitPluginFormat::getDefaultLocationsToSearch() | const FileSearchPath AudioUnitPluginFormat::getDefaultLocationsToSearch() | ||||
| { | { | ||||
| return FileSearchPath ("(Default AudioUnit locations)"); | |||||
| return FileSearchPath ("/(Default AudioUnit locations)"); | |||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -38,7 +38,7 @@ | |||||
| See also SystemStats::getJUCEVersion() for a string version. | See also SystemStats::getJUCEVersion() for a string version. | ||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 46 | |||||
| #define JUCE_MINOR_VERSION 50 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -442,6 +442,26 @@ public: | |||||
| lock.exit(); | 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. | /** Removes an object from the array. | ||||
| @@ -46,14 +46,13 @@ namespace zlibNamespace | |||||
| #define ZLIB_INTERNAL | #define ZLIB_INTERNAL | ||||
| #define NO_DUMMY_DECL | #define NO_DUMMY_DECL | ||||
| #include "zlib/zlib.h" | #include "zlib/zlib.h" | ||||
| #include "zlib/adler32.c" | #include "zlib/adler32.c" | ||||
| #include "zlib/compress.c" | #include "zlib/compress.c" | ||||
| #undef DO1 | #undef DO1 | ||||
| #undef DO8 | #undef DO8 | ||||
| #include "zlib/crc32.c" | #include "zlib/crc32.c" | ||||
| #include "zlib/deflate.c" | #include "zlib/deflate.c" | ||||
| #include "zlib/infback.c" | |||||
| //#include "zlib/infback.c" | |||||
| #include "zlib/inffast.c" | #include "zlib/inffast.c" | ||||
| #undef PULLBYTE | #undef PULLBYTE | ||||
| #undef LOAD | #undef LOAD | ||||
| @@ -65,7 +64,7 @@ namespace zlibNamespace | |||||
| #include "zlib/inflate.c" | #include "zlib/inflate.c" | ||||
| #include "zlib/inftrees.c" | #include "zlib/inftrees.c" | ||||
| #include "zlib/trees.c" | #include "zlib/trees.c" | ||||
| #include "zlib/uncompr.c" | |||||
| //#include "zlib/uncompr.c" | |||||
| #include "zlib/zutil.c" | #include "zlib/zutil.c" | ||||
| #undef Byte | #undef Byte | ||||
| } | } | ||||
| @@ -264,7 +264,8 @@ bool ThreadPool::removeJob (ThreadPoolJob* const job, | |||||
| } | } | ||||
| bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, | bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, | ||||
| const int timeOutMs) | |||||
| const int timeOutMs, | |||||
| const bool deleteInactiveJobs) | |||||
| { | { | ||||
| lock.enter(); | lock.enter(); | ||||
| @@ -280,6 +281,9 @@ bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, | |||||
| else | else | ||||
| { | { | ||||
| jobs.remove (i); | jobs.remove (i); | ||||
| if (deleteInactiveJobs) | |||||
| delete job; | |||||
| } | } | ||||
| } | } | ||||
| @@ -218,11 +218,16 @@ public: | |||||
| methods called to try to interrupt them | methods called to try to interrupt them | ||||
| @param timeOutMilliseconds the length of time this method should wait for all the jobs to finish | @param timeOutMilliseconds the length of time this method should wait for all the jobs to finish | ||||
| before giving up and returning false | 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 | @returns true if all jobs are successfully stopped and removed; false if the timeout period | ||||
| expires while waiting for them to stop | expires while waiting for them to stop | ||||
| */ | */ | ||||
| bool removeAllJobs (const bool interruptRunningJobs, | bool removeAllJobs (const bool interruptRunningJobs, | ||||
| const int timeOutMilliseconds); | |||||
| const int timeOutMilliseconds, | |||||
| const bool deleteInactiveJobs = false); | |||||
| /** Returns the number of jobs currently running or queued. | /** Returns the number of jobs currently running or queued. | ||||
| */ | */ | ||||