|
- /*
- ==============================================================================
-
- 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_RTASCompileFlags.h"
-
- #ifdef _MSC_VER
- // the Digidesign projects all use a struct alignment of 2..
- #pragma pack (2)
- #pragma warning (disable: 4267)
-
- #include "ForcedInclude.h"
- #include "Mac2Win.H"
- #endif
-
- /* Note about include paths
- ------------------------
-
- To be able to include all the Digidesign headers correctly, you'll need to add this
- lot to your include path:
-
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\EffectClasses
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses\Interfaces
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Utilities
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\RTASP_Adapt
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\CoreClasses
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Controls
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Meters
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ViewClasses
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\DSPClasses
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Interfaces
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\common
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\common\Platform
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\SignalProcessing\Public
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugIns\DSPManager\Interfaces
- c:\yourdirectory\PT_711_SDK\AlturaPorts\SADriver\Interfaces
- c:\yourdirectory\PT_711_SDK\AlturaPorts\DigiPublic\Interfaces
- c:\yourdirectory\PT_711_SDK\AlturaPorts\Fic\Interfaces\DAEClient
- c:\yourdirectory\PT_711_SDK\AlturaPorts\NewFileLibs\Cmn
- c:\yourdirectory\PT_711_SDK\AlturaPorts\NewFileLibs\DOA
- c:\yourdirectory\PT_711_SDK\AlturaPorts\AlturaSource\PPC_H
- c:\yourdirectory\PT_711_SDK\AlturaPorts\AlturaSource\AppSupport
- */
-
- #include "CEffectGroupMIDI.h"
- #include "CEffectProcessMIDI.h"
- #include "CEffectProcessRTAS.h"
- #include "CCustomView.h"
- #include "CEffectTypeRTAS.h"
- #include "CPluginControl.h"
- #include "CPluginControl_OnOff.h"
-
- //==============================================================================
- #include "../../juce_AudioFilterBase.h"
- #include "../../juce_AudioFilterEditor.h"
- #include "../../juce_IncludeCharacteristics.h"
- #undef Component
-
- //==============================================================================
- #if JUCE_WIN32
- extern void JUCE_CALLTYPE attachSubWindow (void* hostWindow, int& titleW, int& titleH, juce::Component* comp);
- extern void JUCE_CALLTYPE resizeHostWindow (void* hostWindow, int& titleW, int& titleH, juce::Component* comp);
- #if ! JucePlugin_EditorRequiresKeyboardFocus
- extern void JUCE_CALLTYPE passFocusToHostWindow (void* hostWindow);
- #endif
- #endif
-
- const int midiBufferSize = 1024;
- const OSType juceChunkType = 'juce';
- static const int bypassControlIndex = 1;
-
-
- //==============================================================================
- static float longToFloat (const long n) throw()
- {
- return (float) ((((double) n) + (double) 0x80000000) / (double) 0xffffffff);
- }
-
- static long floatToLong (const float n) throw()
- {
- return roundDoubleToInt (jlimit (-(double) 0x80000000,
- (double) 0x7fffffff,
- n * (double) 0xffffffff - (double) 0x80000000));
- }
-
- //==============================================================================
- class JucePlugInProcess : public CEffectProcessMIDI,
- public CEffectProcessRTAS,
- public AudioFilterBase::HostCallbacks,
- public AsyncUpdater
- {
- public:
- //==============================================================================
- JucePlugInProcess()
- : channels (0),
- prepared (false),
- midiBufferNode (0),
- midiTransport (0),
- sampleRate (44100.0)
- {
- juceFilter = createPluginFilter();
- jassert (juceFilter != 0);
-
- AddChunk (juceChunkType, "Juce Audio Plugin Data");
- }
-
- ~JucePlugInProcess()
- {
- if (mLoggedIn)
- MIDILogOut();
-
- deleteAndZero (midiBufferNode);
- deleteAndZero (midiTransport);
-
- if (prepared)
- juceFilter->releaseResources();
-
- delete juceFilter;
- juce_free (channels);
- }
-
- //==============================================================================
- class JuceCustomUIView : public CCustomView
- {
- public:
- //==============================================================================
- JuceCustomUIView (AudioFilterBase* const filter_)
- : filter (filter_),
- editorComp (0),
- wrapper (0)
- {
- // setting the size in here crashes PT for some reason, so keep it simple..
- }
-
- ~JuceCustomUIView()
- {
- deleteEditorComp();
- }
-
- //==============================================================================
- void updateSize()
- {
- if (editorComp == 0)
- {
- editorComp = filter->createEditorIfNeeded();
- jassert (editorComp != 0);
- }
-
- Rect r;
- r.left = 0;
- r.top = 0;
- r.right = editorComp->getWidth();
- r.bottom = editorComp->getHeight();
-
- SetRect (&r);
- }
-
- void attachToWindow (GrafPtr port)
- {
- if (port != 0)
- {
- updateSize();
-
- #if JUCE_WIN32
- void* const hostWindow = (void*) ASI_GethWnd ((WindowPtr) port);
- #else
- void* const hostWindow = (void*) GetWindowFromPort (port);
- #endif
- deleteAndZero (wrapper);
-
- wrapper = new EditorCompWrapper (hostWindow, editorComp, this);
- }
- else
- {
- deleteEditorComp();
- }
- }
-
- void DrawContents (Rect* r)
- {
- if (wrapper != 0)
- {
- ComponentPeer* const peer = wrapper->getPeer();
-
- if (peer != 0)
- {
- #if JUCE_WIN32
- // (seems to be required in PT6.4, but not in 7.x)
- peer->repaint (0, 0, wrapper->getWidth(), wrapper->getHeight());
-
- #elif JUCE_PPC
- // This crap is needed because if you resize a window, PT doesn't
- // update its clip region, so only part of your new window gets drawn.
- // This overrides the clipping region that's being passed into the Draw
- // method.
- Rect visible;
- GetVisibleRect (&visible);
-
- RestoreFocus();
- Focus (&visible);
- #endif
- peer->performAnyPendingRepaintsNow();
- }
- }
- }
-
- void DrawBackground (Rect* r)
- {
- }
-
- //==============================================================================
- private:
- AudioFilterBase* const filter;
- juce::Component* wrapper;
- AudioFilterEditor* editorComp;
-
- void deleteEditorComp()
- {
- if (editorComp != 0)
- {
- PopupMenu::dismissAllActiveMenus();
-
- juce::Component* const modalComponent = juce::Component::getCurrentlyModalComponent();
- if (modalComponent != 0)
- modalComponent->exitModalState (0);
-
- filter->editorBeingDeleted (editorComp);
- deleteAndZero (editorComp);
- deleteAndZero (wrapper);
- }
- }
-
- //==============================================================================
- // A component to hold the AudioFilterEditor, and cope with some housekeeping
- // chores when it changes or repaints.
- class EditorCompWrapper : public juce::Component,
- #if JUCE_MAC
- public Timer
- #else
- public FocusChangeListener
- #endif
- {
- public:
- EditorCompWrapper (void* const hostWindow_,
- AudioFilterEditor* const editorComp,
- JuceCustomUIView* const owner_)
- : hostWindow (hostWindow_),
- owner (owner_),
- titleW (0),
- titleH (0)
- #if JUCE_MAC
- , forcedRepaintTimer (0)
- #endif
- {
- #if ! JucePlugin_EditorRequiresKeyboardFocus
- setWantsKeyboardFocus (false);
- #endif
- setOpaque (true);
- setBroughtToFrontOnMouseClick (true);
- setBounds (editorComp->getBounds());
- editorComp->setTopLeftPosition (0, 0);
- addAndMakeVisible (editorComp);
-
- #if JUCE_WIN32
- attachSubWindow (hostWindow, titleW, titleH, this);
- setVisible (true);
- #else
- SetAutomaticControlDragTrackingEnabledForWindow ((WindowRef) hostWindow_, true);
-
- WindowAttributes attributes;
- GetWindowAttributes ((WindowRef) hostWindow_, &attributes);
-
- parentView = 0;
-
- if ((attributes & kWindowCompositingAttribute) != 0)
- {
- HIViewRef root = HIViewGetRoot ((WindowRef) hostWindow_);
- HIViewFindByID (root, kHIViewWindowContentID, &parentView);
-
- if (parentView == 0)
- parentView = root;
- }
- else
- {
- GetRootControl ((WindowRef) hostWindow_, (ControlRef*) &parentView);
-
- if (parentView == 0)
- CreateRootControl ((WindowRef) hostWindow_, (ControlRef*) &parentView);
- }
-
- jassert (parentView != 0);
- Rect clientRect;
- GetWindowBounds ((WindowRef) hostWindow, kWindowContentRgn, &clientRect);
-
- titleW = clientRect.right - clientRect.left;
- titleH = jmax (0, (clientRect.bottom - clientRect.top) - getHeight());
- setTopLeftPosition (0, 0);
-
- HIViewSetNeedsDisplay (parentView, true);
-
- setVisible (true);
- addToDesktop (ComponentPeer::windowRepaintedExplictly, (void*) parentView);
-
- HIViewRef pluginView = HIViewGetFirstSubview (parentView);
-
- #if ! JucePlugin_EditorRequiresKeyboardFocus
- HIViewSetActivated (pluginView, false);
- #endif
- /* This is a convoluted and desperate workaround for a Digi (or maybe Apple)
- layout bug. Until the parent control gets some kind of mouse-move
- event, then our plugin's HIView remains stuck at (0, 0) in the
- window (despite drawing correctly), which blocks mouse events from
- getting to the widgets above it.
-
- After days of frustration the only hack I can find that works
- is to use this arcane function to redirect mouse events to
- the parent, while running a timer to spot the moment when our
- view mysteriously snaps back to its correct location.
-
- If anyone at Digi or Apple is reading this and they realise that it's
- their fault, could they please give me back the week of my life that
- they made me waste on this rubbish. Thankyou.
- */
- SetControlSupervisor (pluginView, parentView);
- startTimer (150);
- #endif
-
- #if JUCE_WIN32 && ! JucePlugin_EditorRequiresKeyboardFocus
- Desktop::getInstance().addFocusChangeListener (this);
- #endif
- }
-
- ~EditorCompWrapper()
- {
- #if JUCE_WIN32 && ! JucePlugin_EditorRequiresKeyboardFocus
- Desktop::getInstance().removeFocusChangeListener (this);
- #endif
-
- #if JUCE_MAC
- delete forcedRepaintTimer;
- #endif
- }
-
- void paint (Graphics& g)
- {
- #if JUCE_MAC
- if (forcedRepaintTimer != 0)
- forcedRepaintTimer->stopTimer();
- #endif
- }
-
- void resized()
- {
- juce::Component* const c = getChildComponent (0);
-
- if (c != 0)
- c->setBounds (0, 0, getWidth(), getHeight());
-
- repaint();
- }
-
- #if JUCE_MAC
- void timerCallback()
- {
- // Wait for the moment when PT deigns to allow our view to
- // take up its actual location (see rant above)
- HIViewRef content = 0;
- HIViewFindByID (HIViewGetRoot ((WindowRef) hostWindow), kHIViewWindowContentID, &content);
- HIPoint p = { 0.0f, 0.0f };
-
- HIViewRef v = HIViewGetFirstSubview (parentView);
- HIViewConvertPoint (&p, v, content);
-
- if (p.y > 12)
- {
- HIViewRef v = HIViewGetFirstSubview (parentView);
- SetControlSupervisor (v, 0);
- stopTimer();
-
- forcedRepaintTimer = new RepaintCheckTimer (*this);
- }
- }
- #endif
-
- #if JUCE_WIN32
- void globalFocusChanged (juce::Component*)
- {
- #if ! JucePlugin_EditorRequiresKeyboardFocus
- if (hasKeyboardFocus (true))
- passFocusToHostWindow (hostWindow);
- #endif
- }
- #endif
-
- void childBoundsChanged (juce::Component* child)
- {
- setSize (child->getWidth(), child->getHeight());
- child->setTopLeftPosition (0, 0);
-
- #if JUCE_WIN32
- resizeHostWindow (hostWindow, titleW, titleH, this);
- #else
- Rect r;
- GetWindowBounds ((WindowRef) hostWindow, kWindowContentRgn, &r);
-
- HIRect p;
- zerostruct (p);
- HIViewConvertRect (&p, parentView, 0); // find the X position of our view in case there's space to the left of it
-
- r.right = r.left + jmax (titleW, ((int) p.origin.x) + getWidth());
- r.bottom = r.top + getHeight() + titleH;
-
- SetWindowBounds ((WindowRef) hostWindow, kWindowContentRgn, &r);
-
- owner->updateSize();
- owner->Invalidate();
- #endif
- }
-
- //==============================================================================
- juce_UseDebuggingNewOperator
-
- #if JUCE_MAC
- protected:
- void internalRepaint (int x, int y, int w, int h)
- {
- Component::internalRepaint (x, y, w, h);
- owner->Invalidate();
-
- if (forcedRepaintTimer != 0 && ! forcedRepaintTimer->isTimerRunning())
- forcedRepaintTimer->startTimer (1000 / 25);
- }
-
- HIViewRef parentView;
- #endif
-
- private:
- void* const hostWindow;
- JuceCustomUIView* const owner;
- int titleW, titleH;
-
- #if JUCE_MAC
- // if PT makes us wait too long for a redraw after we've
- // asked for one, this should kick in and force one to happen
- class RepaintCheckTimer : public Timer
- {
- public:
- RepaintCheckTimer (EditorCompWrapper& owner_)
- : owner (owner_)
- {
- }
-
- void timerCallback()
- {
- stopTimer();
- ComponentPeer* const peer = owner.getPeer();
-
- if (peer != 0)
- peer->performAnyPendingRepaintsNow();
- }
-
- EditorCompWrapper& owner;
- };
-
- RepaintCheckTimer* forcedRepaintTimer;
- #endif
- };
- };
-
- JuceCustomUIView* getView() const
- {
- return dynamic_cast <JuceCustomUIView*> (fOurPlugInView);
- }
-
- void GetViewRect (Rect* size)
- {
- if (getView() != 0)
- getView()->updateSize();
-
- CEffectProcessRTAS::GetViewRect (size);
- }
-
- CPlugInView* CreateCPlugInView()
- {
- return new JuceCustomUIView (juceFilter);
- }
-
- void SetViewPort (GrafPtr port)
- {
- CEffectProcessRTAS::SetViewPort (port);
-
- if (getView() != 0)
- getView()->attachToWindow (port);
- }
-
- //==============================================================================
- protected:
- ComponentResult GetDelaySamplesLong (long* aNumSamples)
- {
- if (aNumSamples != 0)
- *aNumSamples = JucePlugin_Latency;
-
- return noErr;
- }
-
- //==============================================================================
- void EffectInit()
- {
- SFicPlugInStemFormats stems;
- GetProcessType()->GetStemFormats (&stems);
-
- juceFilter->setPlayConfigDetails (fNumInputs, fNumOutputs,
- juceFilter->getSampleRate(), juceFilter->getBlockSize());
-
- AddControl (new CPluginControl_OnOff ('bypa', "Master Bypass\nMastrByp\nMByp\nByp", false, true));
- DefineMasterBypassControlIndex (bypassControlIndex);
-
- for (int i = 0; i < juceFilter->getNumParameters(); ++i)
- AddControl (new JucePluginControl (juceFilter, i));
-
- // we need to do this midi log-in to get timecode, regardless of whether
- // the plugin actually uses midi...
- if (MIDILogIn() == noErr)
- {
- #if JucePlugin_WantsMidiInput
- CEffectType* const type = dynamic_cast <CEffectType*> (this->GetProcessType());
-
- if (type != 0)
- {
- char nodeName [64];
- type->GetProcessTypeName (63, nodeName);
- p2cstrcpy (nodeName, reinterpret_cast <unsigned char*> (nodeName));
-
- midiBufferNode = new CEffectMIDIOtherBufferedNode (&mMIDIWorld,
- 8192,
- eLocalNode,
- nodeName,
- midiBuffer);
-
- midiBufferNode->Initialize (1, true);
- }
- #endif
- }
-
- midiTransport = new CEffectMIDITransport (&mMIDIWorld);
-
- juceFilter->setHostCallbacks (this);
- }
-
- void handleAsyncUpdate()
- {
- if (! prepared)
- {
- sampleRate = gProcessGroup->GetSampleRate();
- jassert (sampleRate > 0);
-
- juce_free (channels);
- channels = (float**) juce_calloc (sizeof (float*) * jmax (juceFilter->getNumInputChannels(),
- juceFilter->getNumOutputChannels()));
-
- juceFilter->setPlayConfigDetails (fNumInputs, fNumOutputs,
- sampleRate, mRTGlobals->mHWBufferSizeInSamples);
-
- juceFilter->prepareToPlay (sampleRate,
- mRTGlobals->mHWBufferSizeInSamples);
-
- prepared = true;
- }
- }
-
- void RenderAudio (float** inputs, float** outputs, long numSamples)
- {
- if (! prepared)
- {
- triggerAsyncUpdate();
- bypassBuffers (inputs, outputs, numSamples);
- return;
- }
-
- if (mBypassed)
- {
- bypassBuffers (inputs, outputs, numSamples);
- return;
- }
-
- #if JucePlugin_WantsMidiInput
- midiEvents.clear();
-
- const Cmn_UInt32 bufferSize = mRTGlobals->mHWBufferSizeInSamples;
-
- if (midiBufferNode->GetAdvanceScheduleTime() != bufferSize)
- midiBufferNode->SetAdvanceScheduleTime (bufferSize);
-
- if (midiBufferNode->FillMIDIBuffer (mRTGlobals->mRunningTime, numSamples) == noErr)
- {
- jassert (midiBufferNode->GetBufferPtr() != 0);
- const int numMidiEvents = midiBufferNode->GetBufferSize();
-
- for (int i = 0; i < numMidiEvents; ++i)
- {
- const DirectMidiPacket& m = midiBuffer[i];
-
- jassert ((int) m.mTimestamp < numSamples);
-
- midiEvents.addEvent (m.mData, m.mLength,
- jlimit (0, (int) numSamples - 1, (int) m.mTimestamp));
- }
- }
- #endif
-
- #if defined (JUCE_DEBUG) || JUCE_LOG_ASSERTIONS
- const int numMidiEventsComingIn = midiEvents.getNumEvents();
- #endif
-
- {
- const ScopedLock sl (juceFilter->getCallbackLock());
-
- const int numIn = juceFilter->getNumInputChannels();
- const int numOut = juceFilter->getNumOutputChannels();
- const int totalChans = jmax (numIn, numOut);
-
- if (juceFilter->isSuspended())
- {
- for (int i = 0; i < numOut; ++i)
- zeromem (outputs [i], sizeof (float) * numSamples);
- }
- else
- {
- {
- int i;
- for (i = 0; i < numOut; ++i)
- {
- channels[i] = outputs [i];
-
- if (i < numIn && inputs != outputs)
- memcpy (outputs [i], inputs[i], sizeof (float) * numSamples);
- }
-
- for (; i < numIn; ++i)
- channels [i] = inputs [i];
- }
-
- AudioSampleBuffer chans (channels, totalChans, numSamples);
-
- juceFilter->processBlock (chans, midiEvents);
- }
- }
-
- if (! midiEvents.isEmpty())
- {
- #if JucePlugin_ProducesMidiOutput
- const uint8* midiEventData;
- int midiEventSize, midiEventPosition;
- MidiBuffer::Iterator i (midiEvents);
-
- while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition))
- {
- // jassert (midiEventPosition >= 0 && midiEventPosition < (int) numSamples);
-
- //xxx
- }
- #else
- // if your plugin creates midi messages, you'll need to set
- // the JucePlugin_ProducesMidiOutput macro to 1 in your
- // JucePluginCharacteristics.h file
- jassert (midiEvents.getNumEvents() <= numMidiEventsComingIn);
- #endif
-
- midiEvents.clear();
- }
- }
-
- //==============================================================================
- ComponentResult GetChunkSize (OSType chunkID, long* size)
- {
- if (chunkID == juceChunkType)
- {
- tempFilterData.setSize (0);
- juceFilter->getStateInformation (tempFilterData);
-
- *size = sizeof (SFicPlugInChunkHeader) + tempFilterData.getSize();
- return noErr;
- }
-
- return CEffectProcessMIDI::GetChunkSize (chunkID, size);
- }
-
- ComponentResult GetChunk (OSType chunkID, SFicPlugInChunk* chunk)
- {
- if (chunkID == juceChunkType)
- {
- if (tempFilterData.getSize() == 0)
- juceFilter->getStateInformation (tempFilterData);
-
- chunk->fSize = sizeof (SFicPlugInChunkHeader) + tempFilterData.getSize();
- tempFilterData.copyTo ((void*) chunk->fData, 0, tempFilterData.getSize());
-
- tempFilterData.setSize (0);
-
- return noErr;
- }
-
- return CEffectProcessMIDI::GetChunk (chunkID, chunk);
- }
-
- ComponentResult SetChunk (OSType chunkID, SFicPlugInChunk* chunk)
- {
- if (chunkID == juceChunkType)
- {
- tempFilterData.setSize (0);
-
- if (chunk->fSize - sizeof (SFicPlugInChunkHeader) > 0)
- {
- juceFilter->setStateInformation ((void*) chunk->fData,
- chunk->fSize - sizeof (SFicPlugInChunkHeader));
- }
-
- return noErr;
- }
-
- return CEffectProcessMIDI::SetChunk (chunkID, chunk);
- }
-
- //==============================================================================
- ComponentResult UpdateControlValue (long controlIndex, long value)
- {
- if (controlIndex != bypassControlIndex)
- juceFilter->setParameter (controlIndex - 2, longToFloat (value));
- else
- mBypassed = (value > 0);
-
- return CProcess::UpdateControlValue (controlIndex, value);
- }
-
- //==============================================================================
- bool JUCE_CALLTYPE getCurrentPositionInfo (AudioFilterBase::CurrentPositionInfo& info)
- {
- // this method can only be called while the plugin is running
- jassert (prepared);
-
- Cmn_Float64 bpm = 120.0;
- Cmn_Int32 num = 4, denom = 4;
- Cmn_Int64 ticks = 0;
- Cmn_Bool isPlaying = false;
-
- if (midiTransport != 0)
- {
- midiTransport->GetCurrentTempo (&bpm);
- midiTransport->IsTransportPlaying (&isPlaying);
- midiTransport->GetCurrentMeter (&num, &denom);
- midiTransport->GetCurrentTickPosition (&ticks);
- }
-
- info.bpm = bpm;
- info.timeSigNumerator = num;
- info.timeSigDenominator = denom;
- info.isPlaying = isPlaying;
- info.isRecording = false;
- info.ppqPosition = ticks / 960000.0;
- info.ppqPositionOfLastBarStart = 0; //xxx no idea how to get this correctly..
-
- // xxx incorrect if there are tempo changes, but there's no
- // other way of getting this info..
- info.timeInSeconds = ticks * (60.0 / 960000.0) / bpm;
-
- double framesPerSec = 24.0;
-
- switch (fTimeCodeInfo.mFrameRate)
- {
- case ficFrameRate_24Frame:
- info.frameRate = AudioFilterBase::CurrentPositionInfo::fps24;
- break;
-
- case ficFrameRate_25Frame:
- info.frameRate = AudioFilterBase::CurrentPositionInfo::fps25;
- framesPerSec = 25.0;
- break;
-
- case ficFrameRate_2997NonDrop:
- info.frameRate = AudioFilterBase::CurrentPositionInfo::fps2997;
- framesPerSec = 29.97002997;
- break;
-
- case ficFrameRate_2997DropFrame:
- info.frameRate = AudioFilterBase::CurrentPositionInfo::fps2997drop;
- framesPerSec = 29.97002997;
- break;
-
- case ficFrameRate_30NonDrop:
- info.frameRate = AudioFilterBase::CurrentPositionInfo::fps30;
- framesPerSec = 30.0;
- break;
-
- case ficFrameRate_30DropFrame:
- info.frameRate = AudioFilterBase::CurrentPositionInfo::fps30drop;
- framesPerSec = 30.0;
- break;
-
- case ficFrameRate_23976:
- // xxx not strictly true..
- info.frameRate = AudioFilterBase::CurrentPositionInfo::fps24;
- framesPerSec = 23.976;
- break;
-
- default:
- info.frameRate = AudioFilterBase::CurrentPositionInfo::fpsUnknown;
- break;
- }
-
- info.editOriginTime = fTimeCodeInfo.mFrameOffset / framesPerSec;
-
- return true;
- }
-
- void JUCE_CALLTYPE informHostOfParameterChange (int index, float newValue)
- {
- if (juceFilter != 0)
- juceFilter->setParameter (index, newValue);
-
- SetControlValue (index + 2, floatToLong (newValue));
- }
-
- void JUCE_CALLTYPE informHostOfStateChange()
- {
- // xxx is there an RTAS equivalent?
- }
-
- //==============================================================================
- private:
- AudioFilterBase* juceFilter;
- MidiBuffer midiEvents;
- CEffectMIDIOtherBufferedNode* midiBufferNode;
- CEffectMIDITransport* midiTransport;
- DirectMidiPacket midiBuffer [midiBufferSize];
-
- juce::MemoryBlock tempFilterData;
- float** channels;
- bool prepared;
- double sampleRate;
-
- void bypassBuffers (float** const inputs, float** const outputs, const long numSamples) const
- {
- for (int i = fNumOutputs; --i >= 0;)
- {
- if (i < fNumInputs)
- memcpy (outputs[i], inputs[i], numSamples * sizeof (float));
- else
- zeromem (outputs[i], numSamples * sizeof (float));
- }
- }
-
- //==============================================================================
- class JucePluginControl : public CPluginControl
- {
- public:
- //==============================================================================
- JucePluginControl (AudioFilterBase* const juceFilter_, const int index_)
- : juceFilter (juceFilter_),
- index (index_)
- {
- }
-
- ~JucePluginControl()
- {
- }
-
- //==============================================================================
- OSType GetID() const { return index + 1; }
- long GetDefaultValue() const { return floatToLong (0); }
- void SetDefaultValue (long) {}
- long GetNumSteps() const { return 0xffffffff; }
-
- long ConvertStringToValue (const char* valueString) const
- {
- return floatToLong (String (valueString).getFloatValue());
- }
-
- Cmn_Bool IsKeyValid(long key) const { return true; }
-
- void GetNameOfLength (char* name, int maxLength, OSType inControllerType) const
- {
- juceFilter->getParameterName (index).copyToBuffer (name, maxLength);
- }
-
- long GetPriority() const { return kFicCooperativeTaskPriority; }
-
- long GetOrientation() const
- {
- return kDAE_LeftMinRightMax | kDAE_BottomMinTopMax
- | kDAE_RotarySingleDotMode | kDAE_RotaryLeftMinRightMax;
- }
-
- long GetControlType() const { return kDAE_ContinuousValues; }
-
- void GetValueString (char* valueString, int maxLength, long value) const
- {
- juceFilter->getParameterText (index).copyToBuffer (valueString, maxLength);
- }
-
- Cmn_Bool IsAutomatable() const { return true; }
-
- private:
- //==============================================================================
- AudioFilterBase* const juceFilter;
- const int index;
-
- JucePluginControl (const JucePluginControl&);
- const JucePluginControl& operator= (const JucePluginControl&);
- };
- };
-
-
- //==============================================================================
- class JucePlugInGroup : public CEffectGroupMIDI
- {
- public:
- //==============================================================================
- JucePlugInGroup()
- {
- DefineManufacturerNamesAndID (JucePlugin_Manufacturer, JucePlugin_RTASManufacturerCode);
- DefinePlugInNamesAndVersion (createRTASName(), JucePlugin_VersionCode);
-
- #ifndef JUCE_DEBUG
- AddGestalt (pluginGestalt_IsCacheable);
- #endif
- }
-
- ~JucePlugInGroup()
- {
- shutdownJuce_GUI();
- shutdownJuce_NonGUI();
- }
-
- //==============================================================================
- void CreateEffectTypes()
- {
- const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations };
- const int numConfigs = numElementsInArray (channelConfigs);
-
- // You need to actually add some configurations to the JucePlugin_PreferredChannelConfigurations
- // value in your JucePluginCharacteristics.h file..
- jassert (numConfigs > 0);
-
- for (int i = 0; i < numConfigs; ++i)
- {
- CEffectType* const type
- = new CEffectTypeRTAS ('jcaa' + i,
- JucePlugin_RTASProductId,
- JucePlugin_RTASCategory);
-
- type->DefineTypeNames (createRTASName());
- type->DefineSampleRateSupport (eSupports48kAnd96kAnd192k);
-
- type->DefineStemFormats (getFormatForChans (channelConfigs [i][0]),
- getFormatForChans (channelConfigs [i][1]));
-
- type->AddGestalt (pluginGestalt_CanBypass);
- type->AddGestalt (pluginGestalt_SupportsVariableQuanta);
- type->AttachEffectProcessCreator (createNewProcess);
-
- AddEffectType (type);
- }
- }
-
- void Initialize()
- {
- CEffectGroupMIDI::Initialize();
- }
-
- //==============================================================================
- private:
- static CEffectProcess* createNewProcess()
- {
- // Juce setup
- #if JUCE_WIN32
- PlatformUtilities::setCurrentModuleInstanceHandle (gThisModule);
- #endif
- initialiseJuce_GUI();
-
- return new JucePlugInProcess();
- }
-
- static const String createRTASName()
- {
- return String (JucePlugin_Name) + T("\n")
- + String (JucePlugin_Name).substring (0, 4);
- }
-
- static EPlugIn_StemFormat getFormatForChans (const int numChans) throw()
- {
- switch (numChans)
- {
- case 1:
- return ePlugIn_StemFormat_Mono;
-
- case 2:
- return ePlugIn_StemFormat_Stereo;
-
- case 3:
- return ePlugIn_StemFormat_LCR;
-
- case 4:
- return ePlugIn_StemFormat_Quad;
-
- case 5:
- return ePlugIn_StemFormat_5dot0;
-
- case 6:
- return ePlugIn_StemFormat_5dot1;
-
- case 7:
- return ePlugIn_StemFormat_6dot1;
-
- case 8:
- return ePlugIn_StemFormat_7dot1;
-
- default:
- jassertfalse // hmm - not a valid number of chans for RTAS..
- break;
- }
-
- return ePlugIn_StemFormat_Generic;
- }
- };
-
- CProcessGroupInterface* CProcessGroup::CreateProcessGroup()
- {
- initialiseJuce_NonGUI();
- return new JucePlugInGroup();
- }
|