@@ -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. | ||||
*/ | */ | ||||