2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
27 // (this is a workaround for a build problem in VC9)
28 #define _DO_NOT_DECLARE_INTERLOCKED_INTRINSICS_IN_MEMORY
32 #include "juce_RTAS_DigiCode_Header.h"
34 #if JucePlugin_Build_RTAS
40 /* Note about include paths
41 ------------------------
43 To be able to include all the Digidesign headers correctly, you'll need to add this
44 lot to your include path:
46 c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\EffectClasses
47 c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses
48 c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses\Interfaces
49 c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Utilities
50 c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\RTASP_Adapt
51 c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\CoreClasses
52 c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Controls
53 c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Meters
54 c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ViewClasses
55 c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\DSPClasses
56 c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Interfaces
57 c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\common
58 c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\common\Platform
59 c:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugins\SignalProcessing\Public
60 C:\yourdirectory\PT_80_SDK\AlturaPorts\TDMPlugIns\DSPManager\Interfaces
61 c:\yourdirectory\PT_80_SDK\AlturaPorts\SADriver\Interfaces
62 c:\yourdirectory\PT_80_SDK\AlturaPorts\DigiPublic\Interfaces
63 c:\yourdirectory\PT_80_SDK\AlturaPorts\Fic\Interfaces\DAEClient
64 c:\yourdirectory\PT_80_SDK\AlturaPorts\NewFileLibs\Cmn
65 c:\yourdirectory\PT_80_SDK\AlturaPorts\NewFileLibs\DOA
66 c:\yourdirectory\PT_80_SDK\AlturaPorts\AlturaSource\PPC_H
67 c:\yourdirectory\PT_80_SDK\AlturaPorts\AlturaSource\AppSupport
68 c:\yourdirectory\PT_80_SDK\AvidCode\AVX2sdk\AVX\avx2\avx2sdk\inc
69 C:\yourdirectory\PT_80_SDK\xplat\AVX\avx2\avx2sdk\inc
71 NB. If you hit a huge pile of bugs around here, make sure that you've not got the
72 Apple QuickTime headers before the PT headers in your path, because there are
73 some filename clashes between them.
76 #include <CEffectGroupMIDI.h>
77 #include <CEffectProcessMIDI.h>
78 #include <CEffectProcessRTAS.h>
79 #include <CCustomView.h>
80 #include <CEffectTypeRTAS.h>
81 #include <CPluginControl.h>
82 #include <CPluginControl_OnOff.h>
83 #include <FicProcessTokens.h>
85 //==============================================================================
87 #pragma pack (push, 8)
90 #include "../juce_PluginHeaders.h"
95 #if JUCE_DEBUGxxx // (the debug lib in the 8.0 SDK fails to link, so we'll stick to the release one...)
96 #define PT_LIB_PATH JucePlugin_WinBag_path "\\Debug\\lib\\"
98 #define PT_LIB_PATH JucePlugin_WinBag_path "\\Release\\lib\\"
101 #pragma comment(lib, PT_LIB_PATH "DAE.lib")
102 #pragma comment(lib, PT_LIB_PATH "DigiExt.lib")
103 #pragma comment(lib, PT_LIB_PATH "DSI.lib")
104 #pragma comment(lib, PT_LIB_PATH "PluginLib.lib")
110 //==============================================================================
112 extern void JUCE_CALLTYPE
attachSubWindow (void* hostWindow
, int& titleW
, int& titleH
, JUCE_NAMESPACE::Component
* comp
);
113 extern void JUCE_CALLTYPE
resizeHostWindow (void* hostWindow
, int& titleW
, int& titleH
, JUCE_NAMESPACE::Component
* comp
);
114 #if ! JucePlugin_EditorRequiresKeyboardFocus
115 extern void JUCE_CALLTYPE
passFocusToHostWindow (void* hostWindow
);
118 extern void* attachSubWindow (void* hostWindowRef
, JUCE_NAMESPACE::Component
* comp
);
119 extern void removeSubWindow (void* nsWindow
, JUCE_NAMESPACE::Component
* comp
);
120 extern void forwardCurrentKeyEventToHostWindow();
123 const int midiBufferSize
= 1024;
124 const OSType juceChunkType
= 'juce';
125 static const int bypassControlIndex
= 1;
127 //==============================================================================
128 /** Somewhere in the codebase of your plugin, you need to implement this function
129 and make it return a new instance of the filter subclass that you're building.
131 extern AudioProcessor
* JUCE_CALLTYPE
createPluginFilter();
133 static int numInstances
= 0;
136 //==============================================================================
137 class JucePlugInProcess
: public CEffectProcessMIDI
,
138 public CEffectProcessRTAS
,
139 public AudioProcessorListener
,
143 //==============================================================================
148 asyncUpdater
= new InternalAsyncUpdater (*this);
149 juceFilter
= createPluginFilter();
150 jassert (juceFilter
!= 0);
152 AddChunk (juceChunkType
, "Juce Audio Plugin Data");
164 midiBufferNode
= nullptr;
165 midiTransport
= nullptr;
168 juceFilter
->releaseResources();
173 if (--numInstances
== 0)
176 // Hack to allow any NSWindows to clear themselves up before returning to PT..
177 for (int i
= 20; --i
>= 0;)
178 MessageManager::getInstance()->runDispatchLoopUntil (1);
185 //==============================================================================
186 class JuceCustomUIView
: public CCustomView
,
190 //==============================================================================
191 JuceCustomUIView (AudioProcessor
* const filter_
,
192 JucePlugInProcess
* const process_
)
196 // setting the size in here crashes PT for some reason, so keep it simple..
204 //==============================================================================
207 if (editorComp
== nullptr)
209 editorComp
= filter
->createEditorIfNeeded();
210 jassert (editorComp
!= nullptr);
213 if (editorComp
->getWidth() != 0 && editorComp
->getHeight() != 0)
221 r
.right
= editorComp
->getWidth();
222 r
.bottom
= editorComp
->getHeight();
225 if ((oldRect
.right
!= r
.right
) || (oldRect
.bottom
!= r
.bottom
))
232 if (! JUCE_NAMESPACE::Component::isMouseButtonDownAnywhere())
236 // Send a token to the host to tell it about the resize
237 SSetProcessWindowResizeToken
token (process
->fRootNameId
, process
->fRootNameId
);
238 FicSDSDispatchToken (&token
);
242 void attachToWindow (GrafPtr port
)
250 void* const hostWindow
= (void*) ASI_GethWnd ((WindowPtr
) port
);
252 void* const hostWindow
= (void*) GetWindowFromPort (port
);
255 wrapper
= new EditorCompWrapper (hostWindow
, editorComp
, this);
257 process
->touchAllParameters();
265 void DrawContents (Rect
*)
268 if (wrapper
!= nullptr)
270 ComponentPeer
* const peer
= wrapper
->getPeer();
274 // (seems to be required in PT6.4, but not in 7.x)
275 peer
->repaint (wrapper
->getLocalBounds());
281 void DrawBackground (Rect
*) {}
283 //==============================================================================
285 AudioProcessor
* const filter
;
286 JucePlugInProcess
* const process
;
287 ScopedPointer
<JUCE_NAMESPACE::Component
> wrapper
;
288 ScopedPointer
<AudioProcessorEditor
> editorComp
;
290 void deleteEditorComp()
292 if (editorComp
!= 0 || wrapper
!= nullptr)
295 PopupMenu::dismissAllActiveMenus();
297 JUCE_NAMESPACE::Component
* const modalComponent
= JUCE_NAMESPACE::Component::getCurrentlyModalComponent();
298 if (modalComponent
!= nullptr)
299 modalComponent
->exitModalState (0);
301 filter
->editorBeingDeleted (editorComp
);
303 editorComp
= nullptr;
308 //==============================================================================
309 // A component to hold the AudioProcessorEditor, and cope with some housekeeping
310 // chores when it changes or repaints.
311 class EditorCompWrapper
: public JUCE_NAMESPACE::Component
313 , public FocusChangeListener
317 EditorCompWrapper (void* const hostWindow_
,
318 Component
* const editorComp
,
319 JuceCustomUIView
* const owner_
)
320 : hostWindow (hostWindow_
),
325 #if ! JucePlugin_EditorRequiresKeyboardFocus
326 setMouseClickGrabsKeyboardFocus (false);
327 setWantsKeyboardFocus (false);
330 setBroughtToFrontOnMouseClick (true);
331 setBounds (editorComp
->getBounds());
332 editorComp
->setTopLeftPosition (0, 0);
333 addAndMakeVisible (editorComp
);
336 attachSubWindow (hostWindow
, titleW
, titleH
, this);
338 nsWindow
= attachSubWindow (hostWindow
, this);
342 #if JUCE_WINDOWS && ! JucePlugin_EditorRequiresKeyboardFocus
343 Desktop::getInstance().addFocusChangeListener (this);
349 #if JUCE_WINDOWS && ! JucePlugin_EditorRequiresKeyboardFocus
350 Desktop::getInstance().removeFocusChangeListener (this);
354 removeSubWindow (nsWindow
, this);
358 void paint (Graphics
&)
364 JUCE_NAMESPACE::Component
* const c
= getChildComponent (0);
367 c
->setBounds (0, 0, getWidth(), getHeight());
373 void globalFocusChanged (JUCE_NAMESPACE::Component
*)
375 #if ! JucePlugin_EditorRequiresKeyboardFocus
376 if (hasKeyboardFocus (true))
377 passFocusToHostWindow (hostWindow
);
382 void childBoundsChanged (JUCE_NAMESPACE::Component
* child
)
384 setSize (child
->getWidth(), child
->getHeight());
385 child
->setTopLeftPosition (0, 0);
388 resizeHostWindow (hostWindow
, titleW
, titleH
, this);
393 void userTriedToCloseWindow()
397 #if JUCE_MAC && JucePlugin_EditorRequiresKeyboardFocus
398 bool keyPressed (const KeyPress
& kp
)
401 forwardCurrentKeyEventToHostWindow();
407 //==============================================================================
408 void* const hostWindow
;
410 JuceCustomUIView
* const owner
;
413 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EditorCompWrapper
);
417 JuceCustomUIView
* getView() const
419 return dynamic_cast <JuceCustomUIView
*> (fOurPlugInView
);
422 void GetViewRect (Rect
* size
)
424 if (getView() != nullptr)
425 getView()->updateSize();
427 CEffectProcessRTAS::GetViewRect (size
);
430 CPlugInView
* CreateCPlugInView()
432 return new JuceCustomUIView (juceFilter
, this);
435 void SetViewPort (GrafPtr port
)
437 CEffectProcessRTAS::SetViewPort (port
);
439 if (getView() != nullptr)
440 getView()->attachToWindow (port
);
443 //==============================================================================
445 ComponentResult
GetDelaySamplesLong (long* aNumSamples
)
447 if (aNumSamples
!= nullptr)
448 *aNumSamples
= juceFilter
!= nullptr ? juceFilter
->getLatencySamples() : 0;
453 //==============================================================================
456 SFicPlugInStemFormats stems
;
457 GetProcessType()->GetStemFormats (&stems
);
459 juceFilter
->setPlayConfigDetails (fNumInputs
, fNumOutputs
,
460 juceFilter
->getSampleRate(), juceFilter
->getBlockSize());
462 AddControl (new CPluginControl_OnOff ('bypa', "Master Bypass\nMastrByp\nMByp\nByp", false, true));
463 DefineMasterBypassControlIndex (bypassControlIndex
);
465 for (int i
= 0; i
< juceFilter
->getNumParameters(); ++i
)
466 AddControl (new JucePluginControl (juceFilter
, i
));
468 // we need to do this midi log-in to get timecode, regardless of whether
469 // the plugin actually uses midi...
470 if (MIDILogIn() == noErr
)
472 #if JucePlugin_WantsMidiInput
473 CEffectType
* const type
= dynamic_cast <CEffectType
*> (this->GetProcessType());
478 type
->GetProcessTypeName (63, nodeName
);
479 p2cstrcpy (nodeName
, reinterpret_cast <unsigned char*> (nodeName
));
481 midiBufferNode
= new CEffectMIDIOtherBufferedNode (&mMIDIWorld
,
487 midiBufferNode
->Initialize (1, true);
492 midiTransport
= new CEffectMIDITransport (&mMIDIWorld
);
494 juceFilter
->setPlayHead (this);
495 juceFilter
->addListener (this);
497 midiEvents
.ensureSize (2048);
500 void handleAsyncUpdate()
504 sampleRate
= gProcessGroup
->GetSampleRate();
505 jassert (sampleRate
> 0);
507 channels
.calloc (jmax (juceFilter
->getNumInputChannels(),
508 juceFilter
->getNumOutputChannels()));
510 juceFilter
->setPlayConfigDetails (fNumInputs
, fNumOutputs
,
511 sampleRate
, mRTGlobals
->mHWBufferSizeInSamples
);
513 juceFilter
->prepareToPlay (sampleRate
,
514 mRTGlobals
->mHWBufferSizeInSamples
);
520 void RenderAudio (float** inputs
, float** outputs
, long numSamples
)
524 asyncUpdater
->triggerAsyncUpdate();
525 bypassBuffers (inputs
, outputs
, numSamples
);
531 bypassBuffers (inputs
, outputs
, numSamples
);
535 #if JucePlugin_WantsMidiInput
538 const Cmn_UInt32 bufferSize
= mRTGlobals
->mHWBufferSizeInSamples
;
540 if (midiBufferNode
!= 0)
542 if (midiBufferNode
->GetAdvanceScheduleTime() != bufferSize
)
543 midiBufferNode
->SetAdvanceScheduleTime (bufferSize
);
545 if (midiBufferNode
->FillMIDIBuffer (mRTGlobals
->mRunningTime
, numSamples
) == noErr
)
547 jassert (midiBufferNode
->GetBufferPtr() != 0);
548 const int numMidiEvents
= midiBufferNode
->GetBufferSize();
550 for (int i
= 0; i
< numMidiEvents
; ++i
)
552 const DirectMidiPacket
& m
= midiBuffer
[i
];
554 jassert ((int) m
.mTimestamp
< numSamples
);
556 midiEvents
.addEvent (m
.mData
, m
.mLength
,
557 jlimit (0, (int) numSamples
- 1, (int) m
.mTimestamp
));
563 #if JUCE_DEBUG || JUCE_LOG_ASSERTIONS
564 const int numMidiEventsComingIn
= midiEvents
.getNumEvents();
565 (void) numMidiEventsComingIn
;
569 const ScopedLock
sl (juceFilter
->getCallbackLock());
571 const int numIn
= juceFilter
->getNumInputChannels();
572 const int numOut
= juceFilter
->getNumOutputChannels();
573 const int totalChans
= jmax (numIn
, numOut
);
575 if (juceFilter
->isSuspended())
577 for (int i
= 0; i
< numOut
; ++i
)
578 zeromem (outputs
[i
], sizeof (float) * numSamples
);
584 for (i
= 0; i
< numOut
; ++i
)
586 channels
[i
] = outputs
[i
];
588 if (i
< numIn
&& inputs
!= outputs
)
589 memcpy (outputs
[i
], inputs
[i
], sizeof (float) * numSamples
);
592 for (; i
< numIn
; ++i
)
593 channels
[i
] = inputs
[i
];
596 AudioSampleBuffer
chans (channels
, totalChans
, numSamples
);
598 juceFilter
->processBlock (chans
, midiEvents
);
602 if (! midiEvents
.isEmpty())
604 #if JucePlugin_ProducesMidiOutput
605 const JUCE_NAMESPACE::uint8
* midiEventData
;
606 int midiEventSize
, midiEventPosition
;
607 MidiBuffer::Iterator
i (midiEvents
);
609 while (i
.getNextEvent (midiEventData
, midiEventSize
, midiEventPosition
))
611 //jassert (midiEventPosition >= 0 && midiEventPosition < (int) numSamples);
614 // if your plugin creates midi messages, you'll need to set
615 // the JucePlugin_ProducesMidiOutput macro to 1 in your
616 // JucePluginCharacteristics.h file
617 jassert (midiEvents
.getNumEvents() <= numMidiEventsComingIn
);
624 //==============================================================================
625 ComponentResult
GetChunkSize (OSType chunkID
, long* size
)
627 if (chunkID
== juceChunkType
)
629 tempFilterData
.setSize (0);
630 juceFilter
->getStateInformation (tempFilterData
);
632 *size
= sizeof (SFicPlugInChunkHeader
) + tempFilterData
.getSize();
636 return CEffectProcessMIDI::GetChunkSize (chunkID
, size
);
639 ComponentResult
GetChunk (OSType chunkID
, SFicPlugInChunk
* chunk
)
641 if (chunkID
== juceChunkType
)
643 if (tempFilterData
.getSize() == 0)
644 juceFilter
->getStateInformation (tempFilterData
);
646 chunk
->fSize
= sizeof (SFicPlugInChunkHeader
) + tempFilterData
.getSize();
647 tempFilterData
.copyTo ((void*) chunk
->fData
, 0, tempFilterData
.getSize());
649 tempFilterData
.setSize (0);
654 return CEffectProcessMIDI::GetChunk (chunkID
, chunk
);
657 ComponentResult
SetChunk (OSType chunkID
, SFicPlugInChunk
* chunk
)
659 if (chunkID
== juceChunkType
)
661 tempFilterData
.setSize (0);
663 if (chunk
->fSize
- sizeof (SFicPlugInChunkHeader
) > 0)
665 juceFilter
->setStateInformation ((void*) chunk
->fData
,
666 chunk
->fSize
- sizeof (SFicPlugInChunkHeader
));
672 return CEffectProcessMIDI::SetChunk (chunkID
, chunk
);
675 //==============================================================================
676 ComponentResult
UpdateControlValue (long controlIndex
, long value
)
678 if (controlIndex
!= bypassControlIndex
)
679 juceFilter
->setParameter (controlIndex
- 2, longToFloat (value
));
681 mBypassed
= (value
> 0);
683 return CProcess::UpdateControlValue (controlIndex
, value
);
686 //==============================================================================
687 bool getCurrentPosition (AudioPlayHead::CurrentPositionInfo
& info
)
689 // this method can only be called while the plugin is running
692 Cmn_Float64 bpm
= 120.0;
693 Cmn_Int32 num
= 4, denom
= 4;
695 Cmn_Bool isPlaying
= false;
697 if (midiTransport
!= 0)
699 midiTransport
->GetCurrentTempo (&bpm
);
700 midiTransport
->IsTransportPlaying (&isPlaying
);
701 midiTransport
->GetCurrentMeter (&num
, &denom
);
703 // (The following is a work-around because GetCurrentTickPosition() doesn't work correctly).
704 Cmn_Int64 sampleLocation
;
707 midiTransport
->GetCurrentRTASSampleLocation (&sampleLocation
);
709 midiTransport
->GetCurrentTDMSampleLocation (&sampleLocation
);
711 midiTransport
->GetCustomTickPosition (&ticks
, sampleLocation
);
715 info
.timeSigNumerator
= num
;
716 info
.timeSigDenominator
= denom
;
717 info
.isPlaying
= isPlaying
;
718 info
.isRecording
= false;
719 info
.ppqPosition
= ticks
/ 960000.0;
720 info
.ppqPositionOfLastBarStart
= 0; //xxx no idea how to get this correctly..
722 // xxx incorrect if there are tempo changes, but there's no
723 // other way of getting this info..
724 info
.timeInSeconds
= ticks
* (60.0 / 960000.0) / bpm
;
726 double framesPerSec
= 24.0;
728 switch (fTimeCodeInfo
.mFrameRate
)
730 case ficFrameRate_24Frame
: info
.frameRate
= AudioPlayHead::fps24
; break;
731 case ficFrameRate_25Frame
: info
.frameRate
= AudioPlayHead::fps25
; framesPerSec
= 25.0; break;
732 case ficFrameRate_2997NonDrop
: info
.frameRate
= AudioPlayHead::fps2997
; framesPerSec
= 29.97002997; break;
733 case ficFrameRate_2997DropFrame
: info
.frameRate
= AudioPlayHead::fps2997drop
; framesPerSec
= 29.97002997; break;
734 case ficFrameRate_30NonDrop
: info
.frameRate
= AudioPlayHead::fps30
; framesPerSec
= 30.0; break;
735 case ficFrameRate_30DropFrame
: info
.frameRate
= AudioPlayHead::fps30drop
; framesPerSec
= 30.0; break;
736 case ficFrameRate_23976
: info
.frameRate
= AudioPlayHead::fps24
; framesPerSec
= 23.976; break;
737 default: info
.frameRate
= AudioPlayHead::fpsUnknown
; break;
740 info
.editOriginTime
= fTimeCodeInfo
.mFrameOffset
/ framesPerSec
;
745 void audioProcessorParameterChanged (AudioProcessor
*, int index
, float newValue
)
747 SetControlValue (index
+ 2, floatToLong (newValue
));
750 void audioProcessorParameterChangeGestureBegin (AudioProcessor
*, int index
)
752 TouchControl (index
+ 2);
755 void audioProcessorParameterChangeGestureEnd (AudioProcessor
*, int index
)
757 ReleaseControl (index
+ 2);
760 void audioProcessorChanged (AudioProcessor
*)
762 // xxx is there an RTAS equivalent?
765 void touchAllParameters()
767 for (int i
= 0; i
< juceFilter
->getNumParameters(); ++i
)
769 audioProcessorParameterChangeGestureBegin (0, i
);
770 audioProcessorParameterChanged (0, i
, juceFilter
->getParameter (i
));
771 audioProcessorParameterChangeGestureEnd (0, i
);
776 // Need to use an intermediate class here rather than inheriting from AsyncUpdater, so that it can
777 // be deleted before shutting down juce in our destructor.
778 class InternalAsyncUpdater
: public AsyncUpdater
781 InternalAsyncUpdater (JucePlugInProcess
& owner_
) : owner (owner_
) {}
782 void handleAsyncUpdate() { owner
.handleAsyncUpdate(); }
785 JucePlugInProcess
& owner
;
788 //==============================================================================
790 AudioProcessor
* juceFilter
;
791 MidiBuffer midiEvents
;
792 ScopedPointer
<CEffectMIDIOtherBufferedNode
> midiBufferNode
;
793 ScopedPointer
<CEffectMIDITransport
> midiTransport
;
794 DirectMidiPacket midiBuffer
[midiBufferSize
];
796 ScopedPointer
<InternalAsyncUpdater
> asyncUpdater
;
798 JUCE_NAMESPACE::MemoryBlock tempFilterData
;
799 HeapBlock
<float*> channels
;
803 static float longToFloat (const long n
) noexcept
805 return (float) ((((double) n
) + (double) 0x80000000) / (double) 0xffffffff);
808 static long floatToLong (const float n
) noexcept
810 return roundToInt (jlimit (-(double) 0x80000000, (double) 0x7fffffff,
811 n
* (double) 0xffffffff - (double) 0x80000000));
814 void bypassBuffers (float** const inputs
, float** const outputs
, const long numSamples
) const
816 for (int i
= fNumOutputs
; --i
>= 0;)
819 memcpy (outputs
[i
], inputs
[i
], numSamples
* sizeof (float));
821 zeromem (outputs
[i
], numSamples
* sizeof (float));
825 //==============================================================================
826 class JucePluginControl
: public CPluginControl
829 //==============================================================================
830 JucePluginControl (AudioProcessor
* const juceFilter_
, const int index_
)
831 : juceFilter (juceFilter_
),
836 //==============================================================================
837 OSType
GetID() const { return index
+ 1; }
838 long GetDefaultValue() const { return floatToLong (0); }
839 void SetDefaultValue (long) {}
840 long GetNumSteps() const { return 0xffffffff; }
842 long ConvertStringToValue (const char* valueString
) const
844 return floatToLong (String (valueString
).getFloatValue());
847 Cmn_Bool
IsKeyValid (long key
) const { return true; }
849 void GetNameOfLength (char* name
, int maxLength
, OSType inControllerType
) const
851 juceFilter
->getParameterName (index
).copyToUTF8 (name
, maxLength
);
854 long GetPriority() const { return kFicCooperativeTaskPriority
; }
856 long GetOrientation() const
858 return kDAE_LeftMinRightMax
| kDAE_BottomMinTopMax
859 | kDAE_RotarySingleDotMode
| kDAE_RotaryLeftMinRightMax
;
862 long GetControlType() const { return kDAE_ContinuousValues
; }
864 void GetValueString (char* valueString
, int maxLength
, long value
) const
866 juceFilter
->getParameterText (index
).copyToUTF8 (valueString
, maxLength
);
869 Cmn_Bool
IsAutomatable() const
871 return juceFilter
->isParameterAutomatable (index
);
875 //==============================================================================
876 AudioProcessor
* const juceFilter
;
879 JUCE_DECLARE_NON_COPYABLE (JucePluginControl
);
883 //==============================================================================
884 class JucePlugInGroup
: public CEffectGroupMIDI
887 //==============================================================================
890 DefineManufacturerNamesAndID (JucePlugin_Manufacturer
, JucePlugin_RTASManufacturerCode
);
891 DefinePlugInNamesAndVersion (createRTASName().toUTF8(), JucePlugin_VersionCode
);
894 AddGestalt (pluginGestalt_IsCacheable
);
903 //==============================================================================
904 void CreateEffectTypes()
906 const short channelConfigs
[][2] = { JucePlugin_PreferredChannelConfigurations
};
907 const int numConfigs
= numElementsInArray (channelConfigs
);
909 // You need to actually add some configurations to the JucePlugin_PreferredChannelConfigurations
910 // value in your JucePluginCharacteristics.h file..
911 jassert (numConfigs
> 0);
913 for (int i
= 0; i
< numConfigs
; ++i
)
915 CEffectType
* const type
916 = new CEffectTypeRTAS ('jcaa' + i
,
917 JucePlugin_RTASProductId
,
918 JucePlugin_RTASCategory
);
920 type
->DefineTypeNames (createRTASName().toUTF8().getAddress());
921 type
->DefineSampleRateSupport (eSupports48kAnd96kAnd192k
);
923 type
->DefineStemFormats (getFormatForChans (channelConfigs
[i
][0] != 0 ? channelConfigs
[i
][0] : channelConfigs
[i
][1]),
924 getFormatForChans (channelConfigs
[i
][1] != 0 ? channelConfigs
[i
][1] : channelConfigs
[i
][0]));
926 type
->AddGestalt (pluginGestalt_CanBypass
);
927 type
->AddGestalt (pluginGestalt_SupportsVariableQuanta
);
928 type
->AttachEffectProcessCreator (createNewProcess
);
930 AddEffectType (type
);
936 CEffectGroupMIDI::Initialize();
939 //==============================================================================
941 static CEffectProcess
* createNewProcess()
944 PlatformUtilities::setCurrentModuleInstanceHandle (gThisModule
);
947 initialiseJuce_GUI();
949 return new JucePlugInProcess();
952 static String
createRTASName()
954 return String (JucePlugin_Name
) + "\n"
955 + String (JucePlugin_Name
).substring (0, 4);
958 static EPlugIn_StemFormat
getFormatForChans (const int numChans
) noexcept
962 case 0: return ePlugIn_StemFormat_Generic
;
963 case 1: return ePlugIn_StemFormat_Mono
;
964 case 2: return ePlugIn_StemFormat_Stereo
;
965 case 3: return ePlugIn_StemFormat_LCR
;
966 case 4: return ePlugIn_StemFormat_Quad
;
967 case 5: return ePlugIn_StemFormat_5dot0
;
968 case 6: return ePlugIn_StemFormat_5dot1
;
969 case 7: return ePlugIn_StemFormat_6dot1
;
970 case 8: return ePlugIn_StemFormat_7dot1
;
972 default: jassertfalse
; break; // hmm - not a valid number of chans for RTAS..
975 return ePlugIn_StemFormat_Generic
;
979 void initialiseMacRTAS();
981 CProcessGroupInterface
* CProcessGroup::CreateProcessGroup()
987 return new JucePlugInGroup();