From 92dda5a2d971f11530fbf87daf251ce13353eac3 Mon Sep 17 00:00:00 2001 From: Tom Poole Date: Tue, 24 May 2022 17:00:24 +0100 Subject: [PATCH] Remove the IAA demo project --- .../Plugins/InterAppAudioEffectPluginDemo.h | 529 ------------------ 1 file changed, 529 deletions(-) delete mode 100644 examples/Plugins/InterAppAudioEffectPluginDemo.h diff --git a/examples/Plugins/InterAppAudioEffectPluginDemo.h b/examples/Plugins/InterAppAudioEffectPluginDemo.h deleted file mode 100644 index 3794a3e9a8..0000000000 --- a/examples/Plugins/InterAppAudioEffectPluginDemo.h +++ /dev/null @@ -1,529 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE examples. - Copyright (c) 2022 - Raw Material Software Limited - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, - WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR - PURPOSE, ARE DISCLAIMED. - - ============================================================================== -*/ - -/******************************************************************************* - The block below describes the properties of this PIP. A PIP is a short snippet - of code that can be read by the Projucer and used to generate a JUCE project. - - BEGIN_JUCE_PIP_METADATA - - name: InterAppAudioEffectPlugin - version: 1.0.0 - vendor: JUCE - website: http://juce.com - description: Inter-app audio effect plugin. - - dependencies: juce_audio_basics, juce_audio_devices, juce_audio_formats, - juce_audio_plugin_client, juce_audio_processors, - juce_audio_utils, juce_core, juce_data_structures, - juce_events, juce_graphics, juce_gui_basics, juce_gui_extra - exporters: xcode_iphone - - moduleFlags: JUCE_STRICT_REFCOUNTEDPOINTER=1 - - type: AudioProcessor - mainClass: IAAEffectProcessor - - useLocalCopy: 1 - - extraPluginFormats: IAA - - END_JUCE_PIP_METADATA - -*******************************************************************************/ - -#pragma once - -#include - -//============================================================================== -// A very simple decaying meter. -class SimpleMeter : public Component, - private Timer -{ -public: - SimpleMeter() - { - startTimerHz (30); - } - - //============================================================================== - void paint (Graphics& g) override - { - g.fillAll (Colours::transparentBlack); - - auto area = g.getClipBounds(); - g.setColour (getLookAndFeel().findColour (Slider::thumbColourId)); - g.fillRoundedRectangle (area.toFloat(), 6.0); - - auto unfilledHeight = area.getHeight() * (1.0 - level); - g.reduceClipRegion (area.getX(), area.getY(), - area.getWidth(), (int) unfilledHeight); - g.setColour (getLookAndFeel().findColour (Slider::trackColourId)); - g.fillRoundedRectangle (area.toFloat(), 6.0); - } - - //============================================================================== - // Called from the audio thread. - void update (float newLevel) - { - // We don't care if maxLevel gets set to zero (in timerCallback) between the - // load and the assignment. - maxLevel = jmax (maxLevel.load(), newLevel); - } - -private: - //============================================================================== - void timerCallback() override - { - auto callbackLevel = maxLevel.exchange (0.0); - - float decayFactor = 0.95f; - - if (callbackLevel > level) - level = callbackLevel; - else if (level > 0.001) - level *= decayFactor; - else - level = 0; - - repaint(); - } - - std::atomic maxLevel {0.0}; - float level = 0; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SimpleMeter) -}; - -//============================================================================== -// A simple Inter-App Audio plug-in with a gain control and some meters. -class IAAEffectProcessor : public AudioProcessor -{ -public: - IAAEffectProcessor() - : AudioProcessor (BusesProperties() - .withInput ("Input", AudioChannelSet::stereo(), true) - .withOutput ("Output", AudioChannelSet::stereo(), true)), - parameters (*this, nullptr, "InterAppAudioEffect", - { std::make_unique (ParameterID { "gain", 1 }, "Gain", NormalisableRange (0.0f, 1.0f), 1.0f / 3.14f) }) - { - } - - //============================================================================== - void prepareToPlay (double, int) override - { - previousGain = *parameters.getRawParameterValue ("gain"); - } - - void releaseResources() override {} - - bool isBusesLayoutSupported (const BusesLayout& layouts) const override - { - if (layouts.getMainInputChannels() > 2) - return false; - - if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet()) - return false; - - return true; - } - - using AudioProcessor::processBlock; - - void processBlock (AudioBuffer& buffer, MidiBuffer&) override - { - float gain = *parameters.getRawParameterValue ("gain"); - - auto totalNumInputChannels = getTotalNumInputChannels(); - auto totalNumOutputChannels = getTotalNumOutputChannels(); - - auto numSamples = buffer.getNumSamples(); - - for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) - buffer.clear (i, 0, buffer.getNumSamples()); - - // Apply the gain to the samples using a ramp to avoid discontinuities in - // the audio between processed buffers. - for (auto channel = 0; channel < totalNumInputChannels; ++channel) - { - buffer.applyGainRamp (channel, 0, numSamples, previousGain, gain); - auto newLevel = buffer.getMagnitude (channel, 0, numSamples); - - meterListeners.call ([=] (MeterListener& l) { l.handleNewMeterValue (channel, newLevel); }); - } - - previousGain = gain; - - // Now ask the host for the current time so we can store it to be displayed later. - updateCurrentTimeInfoFromHost (lastPosInfo); - } - - //============================================================================== - AudioProcessorEditor* createEditor() override - { - return new IAAEffectEditor (*this, parameters); - } - - bool hasEditor() const override { return true; } - - //============================================================================== - const String getName() const override { return "InterAppAudioEffectPlugin"; } - bool acceptsMidi() const override { return false; } - bool producesMidi() const override { return false; } - double getTailLengthSeconds() const override { return 0.0; } - - //============================================================================== - int getNumPrograms() override { return 1; } - int getCurrentProgram() override { return 0; } - void setCurrentProgram (int) override {} - const String getProgramName (int) override { return "None"; } - void changeProgramName (int, const String&) override {} - - //============================================================================== - void getStateInformation (MemoryBlock& destData) override - { - if (auto xml = parameters.state.createXml()) - copyXmlToBinary (*xml, destData); - } - - void setStateInformation (const void* data, int sizeInBytes) override - { - if (auto xmlState = getXmlFromBinary (data, sizeInBytes)) - if (xmlState->hasTagName (parameters.state.getType())) - parameters.state = ValueTree::fromXml (*xmlState); - } - - //============================================================================== - bool updateCurrentTimeInfoFromHost (AudioPlayHead::CurrentPositionInfo& posInfo) - { - if (auto* ph = getPlayHead()) - { - AudioPlayHead::CurrentPositionInfo newTime; - - if (ph->getCurrentPosition (newTime)) - { - posInfo = newTime; // Successfully got the current time from the host. - return true; - } - } - - // If the host fails to provide the current time, we'll just reset our copy to a default. - lastPosInfo.resetToDefault(); - - return false; - } - - // Allow an IAAAudioProcessorEditor to register as a listener to receive new - // meter values directly from the audio thread. - struct MeterListener - { - virtual ~MeterListener() {} - - virtual void handleNewMeterValue (int, float) = 0; - }; - - void addMeterListener (MeterListener& listener) { meterListeners.add (&listener); } - void removeMeterListener (MeterListener& listener) { meterListeners.remove (&listener); } - - -private: - //============================================================================== - class IAAEffectEditor : public AudioProcessorEditor, - private IAAEffectProcessor::MeterListener, - private Timer - { - public: - IAAEffectEditor (IAAEffectProcessor& p, - AudioProcessorValueTreeState& vts) - : AudioProcessorEditor (p), - iaaEffectProcessor (p), - parameters (vts) - { - // Register for meter value updates. - iaaEffectProcessor.addMeterListener (*this); - - gainSlider.setSliderStyle (Slider::SliderStyle::LinearVertical); - gainSlider.setTextBoxStyle (Slider::TextEntryBoxPosition::TextBoxAbove, false, 60, 20); - addAndMakeVisible (gainSlider); - - for (auto& meter : meters) - addAndMakeVisible (meter); - - // Configure all the graphics for the transport control. - - transportText.setFont (Font (Font::getDefaultMonospacedFontName(), 18.0f, Font::plain)); - transportText.setJustificationType (Justification::topLeft); - addChildComponent (transportText); - - Path rewindShape; - rewindShape.addRectangle (0.0, 0.0, 5.0, buttonSize); - rewindShape.addTriangle (0.0, buttonSize * 0.5f, buttonSize, 0.0, buttonSize, buttonSize); - rewindButton.setShape (rewindShape, true, true, false); - rewindButton.onClick = [this] - { - if (transportControllable()) - iaaEffectProcessor.getPlayHead()->transportRewind(); - }; - addChildComponent (rewindButton); - - Path playShape; - playShape.addTriangle (0.0, 0.0, 0.0, buttonSize, buttonSize, buttonSize / 2); - playButton.setShape (playShape, true, true, false); - playButton.onClick = [this] - { - if (transportControllable()) - iaaEffectProcessor.getPlayHead()->transportPlay (! lastPosInfo.isPlaying); - }; - addChildComponent (playButton); - - Path recordShape; - recordShape.addEllipse (0.0, 0.0, buttonSize, buttonSize); - recordButton.setShape (recordShape, true, true, false); - recordButton.onClick = [this] - { - if (transportControllable()) - iaaEffectProcessor.getPlayHead()->transportRecord (! lastPosInfo.isRecording); - }; - addChildComponent (recordButton); - - // Configure the switch to host button. - - switchToHostButtonLabel.setFont (Font (Font::getDefaultMonospacedFontName(), 18.0f, Font::plain)); - switchToHostButtonLabel.setJustificationType (Justification::centredRight); - switchToHostButtonLabel.setText ("Switch to\nhost app:", dontSendNotification); - addChildComponent (switchToHostButtonLabel); - - switchToHostButton.onClick = [this] - { - if (transportControllable()) - { - PluginHostType hostType; - hostType.switchToHostApplication(); - } - }; - addChildComponent (switchToHostButton); - - auto screenSize = Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea; - setSize (screenSize.getWidth(), screenSize.getHeight()); - - resized(); - - startTimerHz (60); - } - - ~IAAEffectEditor() override - { - iaaEffectProcessor.removeMeterListener (*this); - } - - //============================================================================== - void paint (Graphics& g) override - { - g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId)); - } - - void resized() override - { - auto area = getBounds().reduced (20); - - gainSlider.setBounds (area.removeFromLeft (60)); - - for (auto& meter : meters) - { - area.removeFromLeft (10); - meter.setBounds (area.removeFromLeft (20)); - } - - area.removeFromLeft (20); - transportText.setBounds (area.removeFromTop (120)); - - auto navigationArea = area.removeFromTop ((int) buttonSize); - rewindButton.setTopLeftPosition (navigationArea.getPosition()); - navigationArea.removeFromLeft ((int) buttonSize + 10); - playButton.setTopLeftPosition (navigationArea.getPosition()); - navigationArea.removeFromLeft ((int) buttonSize + 10); - recordButton.setTopLeftPosition (navigationArea.getPosition()); - - area.removeFromTop (30); - - auto appSwitchArea = area.removeFromTop ((int) buttonSize); - switchToHostButtonLabel.setBounds (appSwitchArea.removeFromLeft (100)); - appSwitchArea.removeFromLeft (5); - switchToHostButton.setBounds (appSwitchArea.removeFromLeft ((int) buttonSize)); - } - - private: - //============================================================================== - // Called from the audio thread. - void handleNewMeterValue (int channel, float value) override - { - meters[(size_t) channel].update (value); - } - - //============================================================================== - void timerCallback () override - { - auto timeInfoSuccess = iaaEffectProcessor.updateCurrentTimeInfoFromHost (lastPosInfo); - transportText.setVisible (timeInfoSuccess); - - if (timeInfoSuccess) - updateTransportTextDisplay(); - - updateTransportButtonsDisplay(); - - updateSwitchToHostDisplay(); - } - - //============================================================================== - bool transportControllable() - { - auto processorPlayHead = iaaEffectProcessor.getPlayHead(); - return processorPlayHead != nullptr && processorPlayHead->canControlTransport(); - } - - //============================================================================== - // quick-and-dirty function to format a timecode string - String timeToTimecodeString (double seconds) - { - auto millisecs = roundToInt (seconds * 1000.0); - auto absMillisecs = std::abs (millisecs); - - return String::formatted ("%02d:%02d:%02d.%03d", - millisecs / 360000, - (absMillisecs / 60000) % 60, - (absMillisecs / 1000) % 60, - absMillisecs % 1000); - } - - // A quick-and-dirty function to format a bars/beats string. - String quarterNotePositionToBarsBeatsString (double quarterNotes, int numerator, int denominator) - { - if (numerator == 0 || denominator == 0) - return "1|1|000"; - - auto quarterNotesPerBar = (numerator * 4 / denominator); - auto beats = (fmod (quarterNotes, quarterNotesPerBar) / quarterNotesPerBar) * numerator; - - auto bar = ((int) quarterNotes) / quarterNotesPerBar + 1; - auto beat = ((int) beats) + 1; - auto ticks = ((int) (fmod (beats, 1.0) * 960.0 + 0.5)); - - return String::formatted ("%d|%d|%03d", bar, beat, ticks); - } - - void updateTransportTextDisplay() - { - MemoryOutputStream displayText; - - displayText << "[" << SystemStats::getJUCEVersion() << "]\n" - << String (lastPosInfo.bpm, 2) << " bpm\n" - << lastPosInfo.timeSigNumerator << '/' << lastPosInfo.timeSigDenominator << "\n" - << timeToTimecodeString (lastPosInfo.timeInSeconds) << "\n" - << quarterNotePositionToBarsBeatsString (lastPosInfo.ppqPosition, - lastPosInfo.timeSigNumerator, - lastPosInfo.timeSigDenominator) << "\n"; - - if (lastPosInfo.isRecording) - displayText << "(recording)"; - else if (lastPosInfo.isPlaying) - displayText << "(playing)"; - - transportText.setText (displayText.toString(), dontSendNotification); - } - - void updateTransportButtonsDisplay() - { - auto visible = iaaEffectProcessor.getPlayHead() != nullptr - && iaaEffectProcessor.getPlayHead()->canControlTransport(); - - if (rewindButton.isVisible() != visible) - { - rewindButton.setVisible (visible); - playButton.setVisible (visible); - recordButton.setVisible (visible); - } - - if (visible) - { - auto playColour = lastPosInfo.isPlaying ? Colours::green : defaultButtonColour; - playButton.setColours (playColour, playColour, playColour); - playButton.repaint(); - - auto recordColour = lastPosInfo.isRecording ? Colours::red : defaultButtonColour; - recordButton.setColours (recordColour, recordColour, recordColour); - recordButton.repaint(); - } - } - - void updateSwitchToHostDisplay() - { - PluginHostType hostType; - auto visible = hostType.isInterAppAudioConnected(); - - if (switchToHostButtonLabel.isVisible() != visible) - { - switchToHostButtonLabel.setVisible (visible); - switchToHostButton.setVisible (visible); - - if (visible) - { - auto icon = hostType.getHostIcon ((int) buttonSize); - switchToHostButton.setImages(false, true, true, - icon, 1.0, Colours::transparentBlack, - icon, 1.0, Colours::transparentBlack, - icon, 1.0, Colours::transparentBlack); - } - } - } - - IAAEffectProcessor& iaaEffectProcessor; - AudioProcessorValueTreeState& parameters; - - const float buttonSize = 30.0f; - const Colour defaultButtonColour = Colours::darkgrey; - ShapeButton rewindButton {"Rewind", defaultButtonColour, defaultButtonColour, defaultButtonColour}; - ShapeButton playButton {"Play", defaultButtonColour, defaultButtonColour, defaultButtonColour}; - ShapeButton recordButton {"Record", defaultButtonColour, defaultButtonColour, defaultButtonColour}; - - Slider gainSlider; - AudioProcessorValueTreeState::SliderAttachment gainAttachment = { parameters, "gain", gainSlider }; - - std::array meters; - - ImageButton switchToHostButton; - Label transportText, switchToHostButtonLabel; - - AudioPlayHead::CurrentPositionInfo lastPosInfo; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IAAEffectEditor) - }; - - //============================================================================== - AudioProcessorValueTreeState parameters; - float previousGain = 0.0f; - - // This keeps a copy of the last set of timing info that was acquired during an - // audio callback - the UI component will display this. - AudioPlayHead::CurrentPositionInfo lastPosInfo; - - ListenerList meterListeners; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IAAEffectProcessor) -};