JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_VST3Common.h
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26#pragma once
27
28#ifndef DOXYGEN
29
30namespace juce
31{
32
34
35//==============================================================================
36#define JUCE_DECLARE_VST3_COM_REF_METHODS \
37 Steinberg::uint32 PLUGIN_API addRef() override { return (Steinberg::uint32) ++refCount; } \
38 Steinberg::uint32 PLUGIN_API release() override { const int r = --refCount; if (r == 0) delete this; return (Steinberg::uint32) r; }
39
40#define JUCE_DECLARE_VST3_COM_QUERY_METHODS \
41 Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID, void** obj) override \
42 { \
43 jassertfalse; \
44 *obj = nullptr; \
45 return Steinberg::kNotImplemented; \
46 }
47
48inline bool doUIDsMatch (const Steinberg::TUID a, const Steinberg::TUID b) noexcept
49{
50 return std::memcmp (a, b, sizeof (Steinberg::TUID)) == 0;
51}
52
53/* Holds a tresult and a pointer to an object.
54
55 Useful for holding intermediate results of calls to queryInterface.
56*/
58{
59public:
60 QueryInterfaceResult() = default;
61
62 QueryInterfaceResult (Steinberg::tresult resultIn, void* ptrIn)
63 : result (resultIn), ptr (ptrIn) {}
64
65 bool isOk() const noexcept { return result == Steinberg::kResultOk; }
66
67 Steinberg::tresult extract (void** obj) const
68 {
69 *obj = result == Steinberg::kResultOk ? ptr : nullptr;
70 return result;
71 }
72
73private:
74 Steinberg::tresult result = Steinberg::kResultFalse;
75 void* ptr = nullptr;
76};
77
78/* Holds a tresult and a pointer to an object.
79
80 Calling InterfaceResultWithDeferredAddRef::extract() will also call addRef
81 on the pointed-to object. It is expected that users will use
82 InterfaceResultWithDeferredAddRef to hold intermediate results of a queryInterface
83 call. When a suitable interface is found, the function can be exited with
84 `return suitableInterface.extract (obj)`, which will set the obj pointer,
85 add a reference to the interface, and return the appropriate result code.
86*/
88{
89public:
91
92 template <typename Ptr>
93 InterfaceResultWithDeferredAddRef (Steinberg::tresult resultIn, Ptr* ptrIn)
94 : result (resultIn, ptrIn),
95 addRefFn (doAddRef<Ptr>) {}
96
97 bool isOk() const noexcept { return result.isOk(); }
98
99 Steinberg::tresult extract (void** obj) const
100 {
101 const auto toReturn = result.extract (obj);
102
103 if (result.isOk() && *obj != nullptr)
104 NullCheckedInvocation::invoke (addRefFn, *obj);
105
106 return toReturn;
107 }
108
109private:
110 template <typename Ptr>
111 static void doAddRef (void* obj) { static_cast<Ptr*> (obj)->addRef(); }
112
114 void (*addRefFn) (void*) = nullptr;
115};
116
117template <typename ClassType> struct UniqueBase {};
118template <typename CommonClassType, typename SourceClassType> struct SharedBase {};
119
120template <typename ToTest, typename CommonClassType, typename SourceClassType>
122 const Steinberg::TUID targetIID,
124{
125 if (! doUIDsMatch (targetIID, CommonClassType::iid))
126 return {};
127
128 return { Steinberg::kResultOk, static_cast<CommonClassType*> (static_cast<SourceClassType*> (std::addressof (toTest))) };
129}
130
131template <typename ToTest, typename ClassType>
133 const Steinberg::TUID targetIID,
135{
137}
138
139template <typename ToTest>
140InterfaceResultWithDeferredAddRef testForMultiple (ToTest&, const Steinberg::TUID) { return {}; }
141
142template <typename ToTest, typename Head, typename... Tail>
144{
145 const auto result = testFor (toTest, targetIID, head);
146
147 if (result.isOk())
148 return result;
149
150 return testForMultiple (toTest, targetIID, tail...);
151}
152
153//==============================================================================
154#if VST_VERSION < 0x030608
155 #define kAmbi1stOrderACN kBFormat
156#endif
157
158//==============================================================================
159inline juce::String toString (const Steinberg::char8* string) noexcept { return juce::String (juce::CharPointer_UTF8 ((juce::CharPointer_UTF8::CharType*) string)); }
160inline juce::String toString (const Steinberg::char16* string) noexcept { return juce::String (juce::CharPointer_UTF16 ((juce::CharPointer_UTF16::CharType*) string)); }
161
162// NB: The casts are handled by a Steinberg::UString operator
163inline juce::String toString (const Steinberg::UString128& string) noexcept { return toString (static_cast<const Steinberg::char16*> (string)); }
164inline juce::String toString (const Steinberg::UString256& string) noexcept { return toString (static_cast<const Steinberg::char16*> (string)); }
165
166inline Steinberg::Vst::TChar* toString (const juce::String& source) noexcept { return reinterpret_cast<Steinberg::Vst::TChar*> (source.toUTF16().getAddress()); }
167
168inline void toString128 (Steinberg::Vst::String128 result, const char* source)
169{
170 Steinberg::UString (result, 128).fromAscii (source);
171}
172
173inline void toString128 (Steinberg::Vst::String128 result, const juce::String& source)
174{
175 Steinberg::UString (result, 128).assign (toString (source));
176}
177
178#if JUCE_WINDOWS
179 static const Steinberg::FIDString defaultVST3WindowType = Steinberg::kPlatformTypeHWND;
180#elif JUCE_MAC
181 static const Steinberg::FIDString defaultVST3WindowType = Steinberg::kPlatformTypeNSView;
182#elif JUCE_LINUX || JUCE_BSD
183 static const Steinberg::FIDString defaultVST3WindowType = Steinberg::kPlatformTypeX11EmbedWindowID;
184#endif
185
186
187//==============================================================================
189 bool isInput, int busIndex)
190{
192
193 if (processor != nullptr)
194 processor->getBusArrangement (isInput ? Steinberg::Vst::kInput : Steinberg::Vst::kOutput,
195 (Steinberg::int32) busIndex, arrangement);
196
197 return arrangement;
198}
199
200static std::optional<Steinberg::Vst::Speaker> getSpeakerType (const AudioChannelSet& set, AudioChannelSet::ChannelType type) noexcept
201{
202 switch (type)
203 {
206 case AudioChannelSet::centre: return (set == AudioChannelSet::mono() ? Steinberg::Vst::kSpeakerM : Steinberg::Vst::kSpeakerC);
207
216 case AudioChannelSet::topMiddle: return Steinberg::Vst::kSpeakerTc; /* kSpeakerTm */
263
265
308 break;
309 }
310
311 return {};
312}
313
315{
316 switch (type)
317 {
329 case Steinberg::Vst::kSpeakerTc: return AudioChannelSet::topMiddle; /* kSpeakerTm */
337 case Steinberg::Vst::kSpeakerM: return ((arr & Steinberg::Vst::kSpeakerC) != 0 ? AudioChannelSet::discreteChannel0 : AudioChannelSet::centre);
377 }
378
379 return {};
380}
381
382namespace detail
383{
384 struct LayoutPair
385 {
388 };
389
390 using namespace Steinberg::Vst::SpeakerArr;
391 using X = AudioChannelSet;
392
393 /* Maps VST3 layouts to the equivalent JUCE channels, in VST3 order.
394
395 The channel types are taken from the equivalent JUCE AudioChannelSet, and then reordered to
396 match the VST3 speaker positions.
397 */
398 const LayoutPair layoutTable[]
399 {
400 { kEmpty, {} },
401 { kMono, { X::centre } },
402 { kStereo, { X::left, X::right } },
403 { k30Cine, { X::left, X::right, X::centre } },
404 { k30Music, { X::left, X::right, X::surround } },
405 { k40Cine, { X::left, X::right, X::centre, X::surround } },
406 { k50, { X::left, X::right, X::centre, X::leftSurround, X::rightSurround } },
407 { k51, { X::left, X::right, X::centre, X::LFE, X::leftSurround, X::rightSurround } },
408 { k60Cine, { X::left, X::right, X::centre, X::leftSurround, X::rightSurround, X::centreSurround } },
409 { k61Cine, { X::left, X::right, X::centre, X::LFE, X::leftSurround, X::rightSurround, X::centreSurround } },
410 { k60Music, { X::left, X::right, X::leftSurround, X::rightSurround, X::leftSurroundSide, X::rightSurroundSide } },
411 { k61Music, { X::left, X::right, X::LFE, X::leftSurround, X::rightSurround, X::leftSurroundSide, X::rightSurroundSide } },
412 { k70Music, { X::left, X::right, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide } },
413 { k70Cine, { X::left, X::right, X::centre, X::leftSurround, X::rightSurround, X::leftCentre, X::rightCentre } },
414 { k71Music, { X::left, X::right, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide } },
415 { k71Cine, { X::left, X::right, X::centre, X::LFE, X::leftSurround, X::rightSurround, X::leftCentre, X::rightCentre } },
416 { k40Music, { X::left, X::right, X::leftSurround, X::rightSurround } },
417
418 { k51_4, { X::left, X::right, X::centre, X::LFE, X::leftSurround, X::rightSurround, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight } },
419 { k50_4, { X::left, X::right, X::centre, X::leftSurround, X::rightSurround, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight } },
420 { k71_2, { X::left, X::right, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topSideLeft, X::topSideRight } },
421 { k70_2, { X::left, X::right, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topSideLeft, X::topSideRight } },
422 { k71_4, { X::left, X::right, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight } },
423 { k70_4, { X::left, X::right, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight } },
424 { k71_6, { X::left, X::right, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } },
425 { k70_6, { X::left, X::right, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } },
426
427 // The VST3 layout uses 'left/right' and 'left-of-center/right-of-center', but the JUCE layout uses 'left/right' and 'wide-left/wide-right'.
428 { k91_4, { X::wideLeft, X::wideRight, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::left, X::right, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight } },
429 { k90_4, { X::wideLeft, X::wideRight, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::left, X::right, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight } },
430 { k91_6, { X::wideLeft, X::wideRight, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::left, X::right, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } },
431 { k90_6, { X::wideLeft, X::wideRight, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::left, X::right, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } },
432 };
433
434 #if JUCE_DEBUG
436 #endif
437}
438
439inline bool isLayoutTableValid()
440{
441 for (const auto& item : detail::layoutTable)
442 if ((size_t) countNumberOfBits ((uint64) item.arrangement) != item.channelOrder.size())
444
446
447 for (const auto& item : detail::layoutTable)
448 arrangements.insert (item.arrangement);
449
450 if (arrangements.size() != (size_t) numElementsInArray (detail::layoutTable))
451 return false; // There's a duplicate speaker arrangement
452
453 return std::all_of (std::begin (detail::layoutTable), std::end (detail::layoutTable), [] (const auto& item)
454 {
455 return std::set<AudioChannelSet::ChannelType> (item.channelOrder).size() == item.channelOrder.size();
456 });
457}
458
460{
461 using namespace Steinberg::Vst;
462 using namespace Steinberg::Vst::SpeakerArr;
463
464 #if JUCE_DEBUG
465 std::call_once (detail::layoutTableCheckedFlag, [] { jassert (isLayoutTableValid()); });
466 #endif
467
468 // Check if this is a layout with a hard-coded conversion
469 const auto arrangementMatches = [arr] (const auto& layoutPair) { return layoutPair.arrangement == arr; };
470 const auto iter = std::find_if (std::begin (detail::layoutTable), std::end (detail::layoutTable), arrangementMatches);
471
472 if (iter != std::end (detail::layoutTable))
473 return iter->channelOrder;
474
475 // There's no hard-coded conversion, so assume that the channels are in the same orders in both layouts.
476 const auto channels = getChannelCount (arr);
478 result.ensureStorageAllocated (channels);
479
480 for (auto i = 0; i < channels; ++i)
481 if (const auto t = getChannelType (arr, getSpeaker (arr, i)))
482 result.add (*t);
483
484 if (getChannelCount (arr) == result.size())
485 return result;
486
487 return {};
488}
489
490struct Ambisonics
491{
492 struct Mapping
493 {
495 AudioChannelSet channelSet;
496 };
497
498 inline static const Mapping mappings[]
499 {
503 };
504
505 Ambisonics() = delete;
506};
507
508static std::optional<Steinberg::Vst::SpeakerArrangement> getVst3SpeakerArrangement (const AudioChannelSet& channels) noexcept
509{
510 using namespace Steinberg::Vst::SpeakerArr;
511
512 #if JUCE_DEBUG
513 std::call_once (detail::layoutTableCheckedFlag, [] { jassert (isLayoutTableValid()); });
514 #endif
515
516 for (const auto& mapping : Ambisonics::mappings)
517 if (channels == mapping.channelSet)
518 return mapping.arrangement;
519
520 const auto channelSetMatches = [&channels] (const auto& layoutPair)
521 {
522 return AudioChannelSet::channelSetWithChannels (layoutPair.channelOrder) == channels;
523 };
524 const auto iter = std::find_if (std::begin (detail::layoutTable), std::end (detail::layoutTable), channelSetMatches);
525
526 if (iter != std::end (detail::layoutTable))
527 return iter->arrangement;
528
530
531 for (const auto& type : channels.getChannelTypes())
532 if (const auto t = getSpeakerType (channels, type))
533 result |= *t;
534
535 if (getChannelCount (result) == channels.size())
536 return result;
537
538 return {};
539}
540
542{
543 using namespace Steinberg::Vst::SpeakerArr;
544
545 for (const auto& mapping : Ambisonics::mappings)
546 if (arr == mapping.arrangement)
548
549 if (const auto order = getSpeakerOrder (arr))
551
552 // VST3 <-> JUCE layout conversion error: report this bug to the JUCE forum
553 return {};
554}
555
556//==============================================================================
557/*
558 Provides fast remapping of the channels on a single bus, from VST3 order to JUCE order.
559
560 For multi-bus plugins, you'll need several instances of this, one per bus.
561*/
562struct ChannelMapping
563{
564 ChannelMapping (const AudioChannelSet& layout, bool activeIn)
565 : indices (makeChannelIndices (layout)), active (activeIn) {}
566
567 explicit ChannelMapping (const AudioChannelSet& layout)
568 : ChannelMapping (layout, true) {}
569
570 explicit ChannelMapping (const AudioProcessor::Bus& bus)
571 : ChannelMapping (bus.getLastEnabledLayout(), bus.isEnabled()) {}
572
573 int getJuceChannelForVst3Channel (int vst3Channel) const { return indices[(size_t) vst3Channel]; }
574
575 size_t size() const { return indices.size(); }
576
577 void setActive (bool x) { active = x; }
578 bool isActive() const { return active; }
579
580private:
581 /* Builds a table that provides the index of the corresponding JUCE channel, given a VST3 channel.
582
583 Depending on the mapping, the VST3 arrangement and JUCE arrangement may not contain channels
584 that map 1:1 via getChannelType. For example, the VST3 7.1 layout contains
585 'kSpeakerLs' which maps to the 'leftSurround' channel type, but the JUCE 7.1 layout does not
586 contain this channel type. As a result, we need to try to map the channels sensibly, even
587 if there's not a 'direct' mapping.
588 */
589 static std::vector<int> makeChannelIndices (const AudioChannelSet& juceArrangement)
590 {
591 const auto order = [&]
592 {
593 const auto fallback = juceArrangement.getChannelTypes();
595
596 if (! vst3Arrangement.has_value())
597 return fallback;
598
600
602 return fallback;
603
604 return *reordered;
605 }();
606
607 std::vector<int> result;
608
609 for (const auto& type : order)
610 result.push_back (juceArrangement.getChannelIndexForType (type));
611
612 return result;
613 }
614
615 std::vector<int> indices;
616 bool active = true;
617};
618
620{
621public:
622 DynamicChannelMapping (const AudioChannelSet& channelSet, bool active)
623 : set (channelSet), map (channelSet, active) {}
624
625 explicit DynamicChannelMapping (const AudioChannelSet& channelSet)
627
628 explicit DynamicChannelMapping (const AudioProcessor::Bus& bus)
629 : DynamicChannelMapping (bus.getLastEnabledLayout(), bus.isEnabled()) {}
630
631 AudioChannelSet getAudioChannelSet() const { return set; }
632 int getJuceChannelForVst3Channel (int vst3Channel) const { return map.getJuceChannelForVst3Channel (vst3Channel); }
633 size_t size() const { return map.size(); }
634
635 /* Returns true if the host has activated this bus. */
636 bool isHostActive() const { return hostActive; }
637 /* Returns true if the AudioProcessor expects this bus to be active. */
638 bool isClientActive() const { return map.isActive(); }
639
640 void setHostActive (bool active) { hostActive = active; }
641 void setClientActive (bool active) { map.setActive (active); }
642
643private:
644 AudioChannelSet set;
645 ChannelMapping map;
646 bool hostActive = false;
647};
648
649//==============================================================================
650inline auto& getAudioBusPointer (detail::Tag<float>, Steinberg::Vst::AudioBusBuffers& data) { return data.channelBuffers32; }
651inline auto& getAudioBusPointer (detail::Tag<double>, Steinberg::Vst::AudioBusBuffers& data) { return data.channelBuffers64; }
652
655{
657 {
658 return std::accumulate (map.begin(), map.end(), 0, [] (auto acc, const auto& item)
659 {
660 return acc + (item.isClientActive() ? (int) item.size() : 0);
661 });
662 };
663
665}
666
667template <typename FloatType>
668class ScratchBuffer
669{
670public:
671 void setSize (int numChannels, int blockSize)
672 {
673 buffer.setSize (numChannels, blockSize);
674 }
675
676 void clear() { channelCounter = 0; }
677
678 auto* getNextChannelBuffer() { return buffer.getWritePointer (channelCounter++); }
679
680 auto getArrayOfWritePointers() { return buffer.getArrayOfWritePointers(); }
681
682private:
683 AudioBuffer<FloatType> buffer;
684 int channelCounter = 0;
685};
686
687template <typename FloatType>
689{
690 return (int) std::distance (buffers, std::find_if (buffers, buffers + num, [] (auto& buf)
691 {
692 return getAudioBusPointer (detail::Tag<FloatType>{}, buf) == nullptr && buf.numChannels > 0;
693 }));
694}
695
696enum class Direction { input, output };
697
698template <Direction direction, typename FloatType, typename Iterator>
699static bool validateLayouts (Iterator first, Iterator last, const std::vector<DynamicChannelMapping>& map)
700{
701 if ((size_t) std::distance (first, last) > map.size())
702 return false;
703
704 auto mapIterator = map.begin();
705
706 for (auto it = first; it != last; ++it, ++mapIterator)
707 {
708 auto& bus = *it;
709 auto** busPtr = getAudioBusPointer (detail::Tag<FloatType>{}, bus);
710 const auto expectedJuceChannels = (int) mapIterator->size();
711 const auto actualVstChannels = (int) bus.numChannels;
713 const auto anyChannelIsNull = std::any_of (busPtr, busPtr + limit, [] (auto* ptr) { return ptr == nullptr; });
714 constexpr auto isInput = direction == Direction::input;
715
718
719 // Null channels are allowed if the bus is inactive
720 if (mapIterator->isHostActive() && (anyChannelIsNull || ! channelCountIsUsable))
721 return false;
722
723 // If this is hit, the destination bus has fewer channels than the source bus.
724 // As a result, some channels will 'go missing', and channel layouts may be invalid.
726 }
727
728 // If the host didn't provide the full complement of buses, it must be because the other
729 // buses are all deactivated.
730 return std::none_of (mapIterator, map.end(), [] (const auto& item) { return item.isHostActive(); });
731}
732
733/*
734 The main purpose of this class is to remap a set of buffers provided by the VST3 host into an
735 equivalent JUCE AudioBuffer using the JUCE channel layout/order.
736
737 An instance of this class handles input and output remapping for a single data type (float or
738 double), matching the FloatType template parameter.
739
740 This is in VST3Common.h, rather than in the VST3_Wrapper.cpp, so that we can test it.
741
742 @see ClientBufferMapper
743*/
744template <typename FloatType>
746{
747public:
748 void prepare (int numChannels, int blockSize)
749 {
750 scratchBuffer.setSize (numChannels, blockSize);
751 channels.reserve ((size_t) jmin (128, numChannels));
752 }
753
754 AudioBuffer<FloatType> getMappedBuffer (Steinberg::Vst::ProcessData& data,
757 {
758 scratchBuffer.clear();
759 channels.clear();
760
762
763 // WaveLab workaround: This host may report the wrong number of inputs/outputs so re-count here
764 const auto vstInputs = countValidBuses<FloatType> (data.inputs, data.numInputs);
765
767 return getBlankBuffer (usedChannels, (int) data.numSamples);
768
769 setUpInputChannels (data, (size_t) vstInputs, scratchBuffer, inputMap, channels);
770 setUpOutputChannels (scratchBuffer, outputMap, channels);
771
772 const auto channelPtr = channels.empty() ? scratchBuffer.getArrayOfWritePointers()
773 : channels.data();
774
775 return { channelPtr, (int) channels.size(), (int) data.numSamples };
776 }
777
778private:
780 size_t vstInputs,
781 ScratchBuffer<FloatType>& scratchBuffer,
783 std::vector<FloatType*>& channels)
784 {
785 for (size_t busIndex = 0; busIndex < map.size(); ++busIndex)
786 {
787 const auto& mapping = map[busIndex];
788
789 if (! mapping.isClientActive())
790 continue;
791
792 const auto originalSize = channels.size();
793
794 for (size_t channelIndex = 0; channelIndex < mapping.size(); ++channelIndex)
795 channels.push_back (scratchBuffer.getNextChannelBuffer());
796
797 if (mapping.isHostActive() && busIndex < vstInputs)
798 {
799 auto& bus = data.inputs[busIndex];
800
801 // Every JUCE channel must have a VST3 channel counterpart
802 jassert (mapping.size() <= static_cast<size_t> (bus.numChannels));
803
804 auto** busPtr = getAudioBusPointer (detail::Tag<FloatType>{}, bus);
805
806 for (size_t channelIndex = 0; channelIndex < mapping.size(); ++channelIndex)
807 {
808 FloatVectorOperations::copy (channels[(size_t) mapping.getJuceChannelForVst3Channel ((int) channelIndex) + originalSize],
809 busPtr[channelIndex],
810 (size_t) data.numSamples);
811 }
812 }
813 else
814 {
815 for (size_t channelIndex = 0; channelIndex < mapping.size(); ++channelIndex)
816 FloatVectorOperations::clear (channels[originalSize + channelIndex], (size_t) data.numSamples);
817 }
818 }
819 }
820
821 static void setUpOutputChannels (ScratchBuffer<FloatType>& scratchBuffer,
823 std::vector<FloatType*>& channels)
824 {
825 for (size_t i = 0, initialBusIndex = 0; i < (size_t) map.size(); ++i)
826 {
827 const auto& mapping = map[i];
828
829 if (mapping.isClientActive())
830 {
831 for (size_t j = 0; j < mapping.size(); ++j)
832 {
833 if (channels.size() <= initialBusIndex + j)
834 channels.push_back (scratchBuffer.getNextChannelBuffer());
835 }
836
837 initialBusIndex += mapping.size();
838 }
839 }
840 }
841
842 AudioBuffer<FloatType> getBlankBuffer (int usedChannels, int usedSamples)
843 {
844 // The host is ignoring the bus layout we requested, so we can't process sensibly!
846
847 // Return a silent buffer for the AudioProcessor to process
848 for (auto i = 0; i < usedChannels; ++i)
849 {
850 channels.push_back (scratchBuffer.getNextChannelBuffer());
851 FloatVectorOperations::clear (channels.back(), usedSamples);
852 }
853
854 return { channels.data(), (int) channels.size(), usedSamples };
855 }
856
858 ScratchBuffer<FloatType> scratchBuffer;
859};
860
861//==============================================================================
862/*
863 Remaps a set of buffers provided by the VST3 host into an equivalent JUCE AudioBuffer using the
864 JUCE channel layout/order.
865
866 An instance of this class can remap to either a float or double JUCE buffer, as necessary.
867
868 Although the VST3 spec requires that the bus layout does not change while the plugin is
869 activated and processing, some hosts get this wrong and try to enable/disable buses during
870 playback. This class attempts to be resilient, and should cope with buses being switched on and
871 off during processing.
872
873 This is in VST3Common.h, rather than in the VST3_Wrapper.cpp, so that we can test it.
874
875 @see ClientBufferMapper
876*/
878{
879public:
880 void updateFromProcessor (const AudioProcessor& processor)
881 {
882 struct Pair
883 {
885 bool isInput;
886 };
887
888 for (const auto& pair : { Pair { inputMap, true }, Pair { outputMap, false } })
889 {
890 if (pair.map.empty())
891 {
892 for (auto i = 0; i < processor.getBusCount (pair.isInput); ++i)
893 pair.map.emplace_back (*processor.getBus (pair.isInput, i));
894 }
895 else
896 {
897 // The number of buses cannot change after creating a VST3 plugin!
898 jassert ((size_t) processor.getBusCount (pair.isInput) == pair.map.size());
899
900 for (size_t i = 0; i < (size_t) processor.getBusCount (pair.isInput); ++i)
901 {
902 pair.map[i] = [&]
903 {
904 DynamicChannelMapping replacement { *processor.getBus (pair.isInput, (int) i) };
905 replacement.setHostActive (pair.map[i].isHostActive());
906 return replacement;
907 }();
908 }
909 }
910 }
911 }
912
913 void prepare (int blockSize)
914 {
915 const auto findNumChannelsWhenAllBusesEnabled = [] (const auto& map)
916 {
917 return std::accumulate (map.cbegin(), map.cend(), 0, [] (auto acc, const auto& item)
918 {
919 return acc + (int) item.size();
920 });
921 };
922
923 const auto numChannels = jmax (findNumChannelsWhenAllBusesEnabled (inputMap),
925
926 floatData .prepare (numChannels, blockSize);
927 doubleData.prepare (numChannels, blockSize);
928 }
929
930 void updateActiveClientBuses (const AudioProcessor::BusesLayout& clientBuses)
931 {
932 if ( (size_t) clientBuses.inputBuses .size() != inputMap .size()
933 || (size_t) clientBuses.outputBuses.size() != outputMap.size())
934 {
936 return;
937 }
938
939 const auto sync = [] (auto& map, auto& client)
940 {
941 for (size_t i = 0; i < map.size(); ++i)
942 {
943 jassert (client[(int) i] == AudioChannelSet::disabled() || client[(int) i] == map[i].getAudioChannelSet());
944 map[i].setClientActive (client[(int) i] != AudioChannelSet::disabled());
945 }
946 };
947
948 sync (inputMap, clientBuses.inputBuses);
949 sync (outputMap, clientBuses.outputBuses);
950 }
951
952 void setInputBusHostActive (size_t bus, bool state) { setHostActive (inputMap, bus, state); }
953 void setOutputBusHostActive (size_t bus, bool state) { setHostActive (outputMap, bus, state); }
954
955 auto& getData (detail::Tag<float>) { return floatData; }
956 auto& getData (detail::Tag<double>) { return doubleData; }
957
958 AudioChannelSet getRequestedLayoutForInputBus (size_t bus) const
959 {
961 }
962
963 AudioChannelSet getRequestedLayoutForOutputBus (size_t bus) const
964 {
966 }
967
970
971private:
972 static void setHostActive (std::vector<DynamicChannelMapping>& map, size_t bus, bool state)
973 {
974 if (bus < map.size())
975 map[bus].setHostActive (state);
976 }
977
978 static AudioChannelSet getRequestedLayoutForBus (const std::vector<DynamicChannelMapping>& map, size_t bus)
979 {
980 if (bus < map.size() && map[bus].isHostActive())
981 return map[bus].getAudioChannelSet();
982
984 }
985
988
991};
992
993//==============================================================================
994/* Holds a buffer in the JUCE channel layout, and a reference to a Vst ProcessData struct, and
995 copies each JUCE channel to the appropriate host output channel when this object goes
996 out of scope.
997*/
998template <typename FloatType>
1000{
1001public:
1008 data (hostData)
1009 {}
1010
1012 : ClientRemappedBuffer (mapperIn.getData (detail::Tag<FloatType>{}),
1013 &mapperIn.getInputMap(),
1014 &mapperIn.getOutputMap(),
1015 hostData)
1016 {}
1017
1019 {
1020 // WaveLab workaround: This host may report the wrong number of inputs/outputs so re-count here
1021 const auto vstOutputs = (size_t) countValidBuses<FloatType> (data.outputs, data.numOutputs);
1022
1025 else
1027 }
1028
1029 AudioBuffer<FloatType> buffer;
1030
1031private:
1032 void copyToHostOutputBuses (size_t vstOutputs) const
1033 {
1034 for (size_t i = 0, juceBusOffset = 0; i < outputMap->size(); ++i)
1035 {
1036 const auto& mapping = (*outputMap)[i];
1037
1038 if (mapping.isHostActive() && i < vstOutputs)
1039 {
1040 auto& bus = data.outputs[i];
1041
1042 // Every VST3 channel must have a JUCE channel counterpart
1043 jassert (static_cast<size_t> (bus.numChannels) <= mapping.size());
1044
1045 if (mapping.isClientActive())
1046 {
1047 for (size_t j = 0; j < static_cast<size_t> (bus.numChannels); ++j)
1048 {
1049 auto* hostChannel = getAudioBusPointer (detail::Tag<FloatType>{}, bus)[j];
1050 const auto juceChannel = juceBusOffset + (size_t) mapping.getJuceChannelForVst3Channel ((int) j);
1051 FloatVectorOperations::copy (hostChannel, buffer.getReadPointer ((int) juceChannel), (size_t) data.numSamples);
1052 }
1053 }
1054 else
1055 {
1056 for (size_t j = 0; j < static_cast<size_t> (bus.numChannels); ++j)
1057 {
1058 auto* hostChannel = getAudioBusPointer (detail::Tag<FloatType>{}, bus)[j];
1059 FloatVectorOperations::clear (hostChannel, (size_t) data.numSamples);
1060 }
1061 }
1062 }
1063
1064 if (mapping.isClientActive())
1065 juceBusOffset += mapping.size();
1066 }
1067 }
1068
1069 void clearHostOutputBuses (size_t vstOutputs) const
1070 {
1071 // The host provided us with an unexpected bus layout.
1073
1074 std::for_each (data.outputs, data.outputs + vstOutputs, [this] (auto& bus)
1075 {
1076 auto** busPtr = getAudioBusPointer (detail::Tag<FloatType>{}, bus);
1077 std::for_each (busPtr, busPtr + bus.numChannels, [this] (auto* ptr)
1078 {
1079 if (ptr != nullptr)
1080 FloatVectorOperations::clear (ptr, (int) data.numSamples);
1081 });
1082 });
1083 }
1084
1087
1090};
1091
1092//==============================================================================
1093/*
1094 Remaps a JUCE buffer to an equivalent VST3 layout.
1095
1096 An instance of this class handles mappings for both float and double buffers, but in a single
1097 direction (input or output).
1098*/
1099class HostBufferMapper
1100{
1101public:
1102 /* Builds a cached map of juce <-> vst3 channel mappings. */
1103 void prepare (std::vector<ChannelMapping> arrangements)
1104 {
1105 mappings = std::move (arrangements);
1106
1107 floatBusMap .resize (mappings.size());
1108 doubleBusMap.resize (mappings.size());
1109 busBuffers .resize (mappings.size());
1110 }
1111
1112 /* Applies the mapping to an AudioBuffer using JUCE channel layout. */
1113 template <typename FloatType>
1114 Steinberg::Vst::AudioBusBuffers* getVst3LayoutForJuceBuffer (AudioBuffer<FloatType>& source)
1115 {
1116 int channelIndexOffset = 0;
1117
1118 for (size_t i = 0; i < mappings.size(); ++i)
1119 {
1120 const auto& mapping = mappings[i];
1121 associateBufferTo (busBuffers[i], get (detail::Tag<FloatType>{})[i], source, mapping, channelIndexOffset);
1122 channelIndexOffset += mapping.isActive() ? (int) mapping.size() : 0;
1123 }
1124
1125 return busBuffers.data();
1126 }
1127
1128private:
1129 template <typename FloatType>
1131
1132 template <typename FloatType>
1133 using BusMap = std::vector<Bus<FloatType>>;
1134
1135 static void assignRawPointer (Steinberg::Vst::AudioBusBuffers& vstBuffers, float** raw) { vstBuffers.channelBuffers32 = raw; }
1136 static void assignRawPointer (Steinberg::Vst::AudioBusBuffers& vstBuffers, double** raw) { vstBuffers.channelBuffers64 = raw; }
1137
1138 template <typename FloatType>
1139 void associateBufferTo (Steinberg::Vst::AudioBusBuffers& vstBuffers,
1140 Bus<FloatType>& bus,
1141 AudioBuffer<FloatType>& buffer,
1142 const ChannelMapping& busMap,
1143 int channelStartOffset) const
1144 {
1145 bus.clear();
1146
1147 for (size_t i = 0; i < busMap.size(); ++i)
1148 {
1149 bus.push_back (busMap.isActive() ? buffer.getWritePointer (channelStartOffset + busMap.getJuceChannelForVst3Channel ((int) i))
1150 : nullptr);
1151 }
1152
1153 assignRawPointer (vstBuffers, bus.data());
1154 vstBuffers.numChannels = (Steinberg::int32) busMap.size();
1155 vstBuffers.silenceFlags = busMap.isActive() ? 0 : std::numeric_limits<Steinberg::uint64>::max();
1156 }
1157
1158 auto& get (detail::Tag<float>) { return floatBusMap; }
1159 auto& get (detail::Tag<double>) { return doubleBusMap; }
1160
1161 BusMap<float> floatBusMap;
1162 BusMap<double> doubleBusMap;
1163
1166};
1167
1168//==============================================================================
1169// We have to trust that Steinberg won't double-delete
1170// NOLINTBEGIN(clang-analyzer-cplusplus.NewDelete)
1171template <class ObjectType>
1172class VSTComSmartPtr
1173{
1174public:
1175 VSTComSmartPtr() = default;
1176 VSTComSmartPtr (const VSTComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); }
1177 ~VSTComSmartPtr() { if (source != nullptr) source->release(); }
1178
1179 explicit operator bool() const noexcept { return operator!= (nullptr); }
1180 ObjectType* get() const noexcept { return source; }
1181 ObjectType& operator*() const noexcept { return *source; }
1182 ObjectType* operator->() const noexcept { return source; }
1183
1184 VSTComSmartPtr& operator= (const VSTComSmartPtr& other)
1185 {
1186 auto p = other;
1187 std::swap (p.source, source);
1188 return *this;
1189 }
1190
1191 VSTComSmartPtr& operator= (std::nullptr_t)
1192 {
1193 return operator= (VSTComSmartPtr{});
1194 }
1195
1196 bool operator== (std::nullptr_t) const noexcept { return source == nullptr; }
1197 bool operator!= (std::nullptr_t) const noexcept { return source != nullptr; }
1198
1199 bool loadFrom (Steinberg::FUnknown* o)
1200 {
1201 *this = nullptr;
1202 return o != nullptr && o->queryInterface (ObjectType::iid, (void**) &source) == Steinberg::kResultOk;
1203 }
1204
1205 bool loadFrom (Steinberg::IPluginFactory* factory, const Steinberg::TUID& uuid)
1206 {
1207 jassert (factory != nullptr);
1208 *this = nullptr;
1209 return factory->createInstance (uuid, ObjectType::iid, (void**) &source) == Steinberg::kResultOk;
1210 }
1211
1213 static auto addOwner (ObjectType* t)
1214 {
1215 return VSTComSmartPtr (t, true);
1216 }
1217
1219 static auto becomeOwner (ObjectType* t)
1220 {
1221 return VSTComSmartPtr (t, false);
1222 }
1223
1224private:
1225 explicit VSTComSmartPtr (ObjectType* object, bool autoAddRef) noexcept : source (object) { if (source != nullptr && autoAddRef) source->addRef(); }
1226 ObjectType* source = nullptr;
1227};
1228
1230template <class ObjectType>
1231auto addVSTComSmartPtrOwner (ObjectType* t)
1232{
1233 return VSTComSmartPtr<ObjectType>::addOwner (t);
1234}
1235
1237template <class ObjectType>
1238auto becomeVSTComSmartPtrOwner (ObjectType* t)
1239{
1240 return VSTComSmartPtr<ObjectType>::becomeOwner (t);
1241}
1242
1243// NOLINTEND(clang-analyzer-cplusplus.NewDelete)
1244
1245//==============================================================================
1246/* This class stores a plugin's preferred MIDI mappings.
1247
1248 The IMidiMapping is normally an extension of the IEditController which
1249 should only be accessed from the UI thread. If we're being strict about
1250 things, then we shouldn't call IMidiMapping functions from the audio thread.
1251
1252 This code is very similar to that found in the audioclient demo code in the
1253 VST3 SDK repo.
1254*/
1255class StoredMidiMapping
1256{
1257public:
1258 StoredMidiMapping()
1259 {
1260 for (auto& channel : channels)
1261 channel.resize (Steinberg::Vst::kCountCtrlNumber);
1262 }
1263
1264 void storeMappings (Steinberg::Vst::IMidiMapping& mapping)
1265 {
1266 for (size_t channelIndex = 0; channelIndex < channels.size(); ++channelIndex)
1267 storeControllers (mapping, channels[channelIndex], channelIndex);
1268 }
1269
1270 /* Returns kNoParamId if there is no mapping for this controller. */
1271 Steinberg::Vst::ParamID getMapping (Steinberg::int16 channel,
1272 Steinberg::Vst::CtrlNumber controller) const noexcept
1273 {
1274 return channels[(size_t) channel][(size_t) controller];
1275 }
1276
1277private:
1278 // Maps controller numbers to ParamIDs
1279 using Controllers = std::vector<Steinberg::Vst::ParamID>;
1280
1281 // Each channel may have a different CC mapping
1282 using Channels = std::array<Controllers, 16>;
1283
1284 static void storeControllers (Steinberg::Vst::IMidiMapping& mapping, Controllers& channel, size_t channelIndex)
1285 {
1286 for (size_t controllerIndex = 0; controllerIndex < channel.size(); ++controllerIndex)
1287 channel[controllerIndex] = getSingleMapping (mapping, channelIndex, controllerIndex);
1288 }
1289
1290 static Steinberg::Vst::ParamID getSingleMapping (Steinberg::Vst::IMidiMapping& mapping,
1291 size_t channelIndex,
1292 size_t controllerIndex)
1293 {
1294 Steinberg::Vst::ParamID result{};
1295 const auto returnCode = mapping.getMidiControllerAssignment (0,
1296 (int16) channelIndex,
1297 (Steinberg::Vst::CtrlNumber) controllerIndex,
1298 result);
1299
1300 return returnCode == Steinberg::kResultTrue ? result : Steinberg::Vst::kNoParamId;
1301 }
1302
1303 Channels channels;
1304};
1305
1306//==============================================================================
1307class MidiEventList : public Steinberg::Vst::IEventList
1308{
1309public:
1310 MidiEventList() = default;
1311 virtual ~MidiEventList() = default;
1312
1313 JUCE_DECLARE_VST3_COM_REF_METHODS
1314 JUCE_DECLARE_VST3_COM_QUERY_METHODS
1315
1316 //==============================================================================
1317 void clear()
1318 {
1319 events.clearQuick();
1320 }
1321
1322 Steinberg::int32 PLUGIN_API getEventCount() override
1323 {
1324 return (Steinberg::int32) events.size();
1325 }
1326
1327 // NB: This has to cope with out-of-range indexes from some plugins.
1328 Steinberg::tresult PLUGIN_API getEvent (Steinberg::int32 index, Steinberg::Vst::Event& e) override
1329 {
1330 if (isPositiveAndBelow ((int) index, events.size()))
1331 {
1332 e = events.getReference ((int) index);
1333 return Steinberg::kResultTrue;
1334 }
1335
1336 return Steinberg::kResultFalse;
1337 }
1338
1339 Steinberg::tresult PLUGIN_API addEvent (Steinberg::Vst::Event& e) override
1340 {
1341 events.add (e);
1342 return Steinberg::kResultTrue;
1343 }
1344
1345 //==============================================================================
1346 static void toMidiBuffer (MidiBuffer& result, Steinberg::Vst::IEventList& eventList)
1347 {
1348 const auto numEvents = eventList.getEventCount();
1349
1350 for (Steinberg::int32 i = 0; i < numEvents; ++i)
1351 {
1353
1354 if (eventList.getEvent (i, e) != Steinberg::kResultOk)
1355 continue;
1356
1357 if (const auto message = toMidiMessage (e))
1358 result.addEvent (*message, e.sampleOffset);
1359 }
1360 }
1361
1362 template <typename Callback>
1363 static void hostToPluginEventList (Steinberg::Vst::IEventList& result,
1364 MidiBuffer& midiBuffer,
1365 StoredMidiMapping& mapping,
1366 Callback&& callback)
1367 {
1368 toEventList (result, midiBuffer, &mapping, callback);
1369 }
1370
1371 static void pluginToHostEventList (Steinberg::Vst::IEventList& result, MidiBuffer& midiBuffer)
1372 {
1373 toEventList (result, midiBuffer, nullptr, [] (auto&&...) {});
1374 }
1375
1376private:
1377 enum class EventConversionKind
1378 {
1379 // Hosted plugins don't expect to receive LegacyMIDICCEvents messages from the host,
1380 // so if we're converting midi from the host to an eventlist, this mode will avoid
1381 // converting to Legacy events where possible.
1382 hostToPlugin,
1383
1384 // If plugins generate MIDI internally, then where possible we should preserve
1385 // these messages as LegacyMIDICCOut events.
1386 pluginToHost
1387 };
1388
1389 template <typename Callback>
1390 static bool sendMappedParameter (const MidiMessage& msg,
1391 StoredMidiMapping* midiMapping,
1392 Callback&& callback)
1393 {
1394 if (midiMapping == nullptr)
1395 return false;
1396
1397 const auto controlEvent = toVst3ControlEvent (msg);
1398
1399 if (! controlEvent.has_value())
1400 return false;
1401
1402 const auto controlParamID = midiMapping->getMapping (createSafeChannel (msg.getChannel()),
1403 controlEvent->controllerNumber);
1404
1405 if (controlParamID != Steinberg::Vst::kNoParamId)
1406 callback (controlParamID, controlEvent->paramValue);
1407
1408 return true;
1409 }
1410
1411 template <typename Callback>
1412 static void processMidiMessage (Steinberg::Vst::IEventList& result,
1413 const MidiMessageMetadata metadata,
1414 StoredMidiMapping* midiMapping,
1415 Callback&& callback)
1416 {
1417 const auto msg = metadata.getMessage();
1418
1419 if (sendMappedParameter (msg, midiMapping, std::forward<Callback> (callback)))
1420 return;
1421
1422 const auto kind = midiMapping != nullptr ? EventConversionKind::hostToPlugin
1423 : EventConversionKind::pluginToHost;
1424
1425 auto maybeEvent = createVstEvent (msg, metadata.data, kind);
1426
1427 if (! maybeEvent.hasValue())
1428 return;
1429
1430 maybeEvent->busIndex = 0;
1431 maybeEvent->sampleOffset = metadata.samplePosition;
1432 result.addEvent (*maybeEvent);
1433 }
1434
1435 /* If mapping is non-null, the conversion is assumed to be host-to-plugin, or otherwise
1436 plugin-to-host.
1437 */
1438 template <typename Callback>
1439 static void toEventList (Steinberg::Vst::IEventList& result,
1440 MidiBuffer& midiBuffer,
1441 StoredMidiMapping* midiMapping,
1442 Callback&& callback)
1443 {
1444 enum { maxNumEvents = 2048 }; // Steinberg's Host Checker states that no more than 2048 events are allowed at once
1445 int numEvents = 0;
1446
1447 for (const auto metadata : midiBuffer)
1448 {
1449 if (++numEvents > maxNumEvents)
1450 break;
1451
1452 processMidiMessage (result, metadata, midiMapping, std::forward<Callback> (callback));
1453 }
1454 }
1455
1456 Array<Steinberg::Vst::Event, CriticalSection> events;
1457 Atomic<int> refCount;
1458
1459 static Steinberg::int16 createSafeChannel (int channel) noexcept { return (Steinberg::int16) jlimit (0, 15, channel - 1); }
1460 static int createSafeChannel (Steinberg::int16 channel) noexcept { return (int) jlimit (1, 16, channel + 1); }
1461
1462 static Steinberg::int16 createSafeNote (int note) noexcept { return (Steinberg::int16) jlimit (0, 127, note); }
1463 static int createSafeNote (Steinberg::int16 note) noexcept { return jlimit (0, 127, (int) note); }
1464
1465 static float normaliseMidiValue (int value) noexcept { return jlimit (0.0f, 1.0f, (float) value / 127.0f); }
1466 static int denormaliseToMidiValue (float value) noexcept { return roundToInt (jlimit (0.0f, 127.0f, value * 127.0f)); }
1467
1468 static Steinberg::Vst::Event createNoteOnEvent (const MidiMessage& msg) noexcept
1469 {
1472 e.noteOn.channel = createSafeChannel (msg.getChannel());
1473 e.noteOn.pitch = createSafeNote (msg.getNoteNumber());
1474 e.noteOn.velocity = normaliseMidiValue (msg.getVelocity());
1475 e.noteOn.length = 0;
1476 e.noteOn.tuning = 0.0f;
1477 e.noteOn.noteId = -1;
1478 return e;
1479 }
1480
1481 static Steinberg::Vst::Event createNoteOffEvent (const MidiMessage& msg) noexcept
1482 {
1485 e.noteOff.channel = createSafeChannel (msg.getChannel());
1486 e.noteOff.pitch = createSafeNote (msg.getNoteNumber());
1487 e.noteOff.velocity = normaliseMidiValue (msg.getVelocity());
1488 e.noteOff.tuning = 0.0f;
1489 e.noteOff.noteId = -1;
1490 return e;
1491 }
1492
1493 static Steinberg::Vst::Event createSysExEvent (const MidiMessage& msg, const uint8* data) noexcept
1494 {
1495 jassert (msg.isSysEx());
1496
1499 e.data.bytes = data;
1500 e.data.size = (uint32) msg.getRawDataSize();
1502 return e;
1503 }
1504
1505 static Steinberg::Vst::Event createLegacyMIDIEvent (int channel, int controlNumber, int value, int value2 = 0)
1506 {
1509 e.midiCCOut.channel = Steinberg::int8 (createSafeChannel (channel));
1510 e.midiCCOut.controlNumber = uint8 (jlimit (0, 255, controlNumber));
1511 e.midiCCOut.value = Steinberg::int8 (createSafeNote (value));
1512 e.midiCCOut.value2 = Steinberg::int8 (createSafeNote (value2));
1513 return e;
1514 }
1515
1516 static Steinberg::Vst::Event createPolyPressureEvent (const MidiMessage& msg)
1517 {
1520 e.polyPressure.channel = createSafeChannel (msg.getChannel());
1521 e.polyPressure.pitch = createSafeNote (msg.getNoteNumber());
1522 e.polyPressure.pressure = normaliseMidiValue (msg.getAfterTouchValue());
1523 e.polyPressure.noteId = -1;
1524 return e;
1525 }
1526
1527 static Steinberg::Vst::Event createChannelPressureEvent (const MidiMessage& msg) noexcept
1528 {
1529 return createLegacyMIDIEvent (msg.getChannel(),
1531 msg.getChannelPressureValue());
1532 }
1533
1534 static Steinberg::Vst::Event createControllerEvent (const MidiMessage& msg) noexcept
1535 {
1536 return createLegacyMIDIEvent (msg.getChannel(),
1537 msg.getControllerNumber(),
1538 msg.getControllerValue());
1539 }
1540
1541 static Steinberg::Vst::Event createCtrlPolyPressureEvent (const MidiMessage& msg) noexcept
1542 {
1543 return createLegacyMIDIEvent (msg.getChannel(),
1545 msg.getNoteNumber(),
1546 msg.getAfterTouchValue());
1547 }
1548
1549 static Steinberg::Vst::Event createPitchWheelEvent (const MidiMessage& msg) noexcept
1550 {
1551 return createLegacyMIDIEvent (msg.getChannel(),
1553 msg.getRawData()[1],
1554 msg.getRawData()[2]);
1555 }
1556
1557 static Steinberg::Vst::Event createProgramChangeEvent (const MidiMessage& msg) noexcept
1558 {
1559 return createLegacyMIDIEvent (msg.getChannel(),
1561 msg.getProgramChangeNumber());
1562 }
1563
1564 static Steinberg::Vst::Event createCtrlQuarterFrameEvent (const MidiMessage& msg) noexcept
1565 {
1566 return createLegacyMIDIEvent (msg.getChannel(),
1568 msg.getQuarterFrameValue());
1569 }
1570
1571 static Optional<Steinberg::Vst::Event> createVstEvent (const MidiMessage& msg,
1572 const uint8* midiEventData,
1573 EventConversionKind kind) noexcept
1574 {
1575 if (msg.isNoteOn())
1576 return createNoteOnEvent (msg);
1577
1578 if (msg.isNoteOff())
1579 return createNoteOffEvent (msg);
1580
1581 if (msg.isSysEx())
1582 return createSysExEvent (msg, midiEventData);
1583
1584 if (msg.isChannelPressure())
1585 return createChannelPressureEvent (msg);
1586
1587 if (msg.isPitchWheel())
1588 return createPitchWheelEvent (msg);
1589
1590 if (msg.isProgramChange())
1591 return createProgramChangeEvent (msg);
1592
1593 if (msg.isController())
1594 return createControllerEvent (msg);
1595
1596 if (msg.isQuarterFrame())
1597 return createCtrlQuarterFrameEvent (msg);
1598
1599 if (msg.isAftertouch())
1600 {
1601 switch (kind)
1602 {
1603 case EventConversionKind::hostToPlugin:
1604 return createPolyPressureEvent (msg);
1605
1606 case EventConversionKind::pluginToHost:
1607 return createCtrlPolyPressureEvent (msg);
1608 }
1609
1611 return {};
1612 }
1613
1614 return {};
1615 }
1616
1617 static Optional<MidiMessage> toMidiMessage (const Steinberg::Vst::LegacyMIDICCOutEvent& e)
1618 {
1619 if (e.controlNumber <= 127)
1620 return MidiMessage::controllerEvent (createSafeChannel (int16 (e.channel)),
1621 createSafeNote (int16 (e.controlNumber)),
1622 createSafeNote (int16 (e.value)));
1623
1624 switch (e.controlNumber)
1625 {
1627 return MidiMessage::channelPressureChange (createSafeChannel (int16 (e.channel)),
1628 createSafeNote (int16 (e.value)));
1629
1631 return MidiMessage::pitchWheel (createSafeChannel (int16 (e.channel)),
1632 (e.value & 0x7f) | ((e.value2 & 0x7f) << 7));
1633
1635 return MidiMessage::programChange (createSafeChannel (int16 (e.channel)),
1636 createSafeNote (int16 (e.value)));
1637
1639 return MidiMessage::quarterFrame (createSafeChannel (int16 (e.channel)),
1640 createSafeNote (int16 (e.value)));
1641
1643 return MidiMessage::aftertouchChange (createSafeChannel (int16 (e.channel)),
1644 createSafeNote (int16 (e.value)),
1645 createSafeNote (int16 (e.value2)));
1646
1647 default:
1648 // If this is hit, we're trying to convert a LegacyMIDICCOutEvent with an unknown controlNumber.
1650 return {};
1651 }
1652 }
1653
1654 static Optional<MidiMessage> toMidiMessage (const Steinberg::Vst::DataEvent& e)
1655 {
1657 {
1658 // Only sysex data messages can be converted to MIDI
1660 return {};
1661 }
1662
1663 const auto header = e.bytes[0];
1664 const auto footer = e.bytes[e.size - 1];
1665
1666 if (header != 0xf0 || footer != 0xf7)
1667 {
1668 // The sysex header/footer bytes are missing
1670 return {};
1671 }
1672
1673 return MidiMessage::createSysExMessage (e.bytes + 1, (int) e.size - 2);
1674 }
1675
1676 static Optional<MidiMessage> toMidiMessage (const Steinberg::Vst::Event& e)
1677 {
1678 switch (e.type)
1679 {
1681 return MidiMessage::noteOn (createSafeChannel (e.noteOn.channel),
1682 createSafeNote (e.noteOn.pitch),
1683 (Steinberg::uint8) denormaliseToMidiValue (e.noteOn.velocity));
1684
1686 return MidiMessage::noteOff (createSafeChannel (e.noteOff.channel),
1687 createSafeNote (e.noteOff.pitch),
1688 (Steinberg::uint8) denormaliseToMidiValue (e.noteOff.velocity));
1689
1691 return MidiMessage::aftertouchChange (createSafeChannel (e.polyPressure.channel),
1692 createSafeNote (e.polyPressure.pitch),
1693 (Steinberg::uint8) denormaliseToMidiValue (e.polyPressure.pressure));
1694
1696 return toMidiMessage (e.data);
1697
1699 return toMidiMessage (e.midiCCOut);
1700
1705 return {};
1706
1707 default:
1708 break;
1709 }
1710
1711 // If this is hit, we've been sent an event type that doesn't exist in the VST3 spec.
1713 return {};
1714 }
1715
1716 //==============================================================================
1717 struct Vst3MidiControlEvent
1718 {
1719 Steinberg::Vst::CtrlNumber controllerNumber;
1720 Steinberg::Vst::ParamValue paramValue;
1721 };
1722
1723 static std::optional<Vst3MidiControlEvent> toVst3ControlEvent (const MidiMessage& msg)
1724 {
1725 if (msg.isController())
1726 return Vst3MidiControlEvent { (Steinberg::Vst::CtrlNumber) msg.getControllerNumber(), msg.getControllerValue() / 127.0 };
1727
1728 if (msg.isPitchWheel())
1729 return Vst3MidiControlEvent { Steinberg::Vst::kPitchBend, msg.getPitchWheelValue() / 16383.0};
1730
1731 if (msg.isChannelPressure())
1732 return Vst3MidiControlEvent { Steinberg::Vst::kAfterTouch, msg.getChannelPressureValue() / 127.0};
1733
1734 return {};
1735 }
1736
1738};
1739
1740//==============================================================================
1741/* Provides very quick polling of all parameter states.
1742
1743 We must iterate all parameters on each processBlock call to check whether any
1744 parameter value has changed. This class attempts to make this polling process
1745 as quick as possible.
1746
1747 The indices here are of type Steinberg::int32, as they are expected to correspond
1748 to parameter information obtained from the IEditController. These indices may not
1749 match the indices of parameters returned from AudioProcessor::getParameters(), so
1750 be careful!
1751*/
1752class CachedParamValues
1753{
1754public:
1755 CachedParamValues() = default;
1756
1757 explicit CachedParamValues (std::vector<Steinberg::Vst::ParamID> paramIdsIn)
1758 : paramIds (std::move (paramIdsIn)), floatCache (paramIds.size()) {}
1759
1760 size_t size() const noexcept { return floatCache.size(); }
1761
1762 Steinberg::Vst::ParamID getParamID (Steinberg::int32 index) const noexcept { return paramIds[(size_t) index]; }
1763
1764 void set (Steinberg::int32 index, float value)
1765 {
1766 floatCache.setValueAndBits ((size_t) index, value, 1);
1767 }
1768
1769 float exchangeWithoutNotifying (Steinberg::int32 index, float value)
1770 {
1771 return floatCache.exchangeValue ((size_t) index, value);
1772 }
1773
1774 float get (Steinberg::int32 index) const noexcept { return floatCache.get ((size_t) index); }
1775
1776 template <typename Callback>
1777 void ifSet (Callback&& callback)
1778 {
1779 floatCache.ifSet ([&] (size_t index, float value, uint32_t)
1780 {
1781 callback ((Steinberg::int32) index, value);
1782 });
1783 }
1784
1785private:
1787 FlaggedFloatCache<1> floatCache;
1788};
1789
1790//==============================================================================
1791/* Ensures that a 'restart' call only ever happens on the main thread. */
1792class ComponentRestarter : private AsyncUpdater
1793{
1794public:
1795 struct Listener
1796 {
1797 virtual ~Listener() = default;
1798 virtual void restartComponentOnMessageThread (int32 flags) = 0;
1799 };
1800
1801 explicit ComponentRestarter (Listener& listenerIn)
1802 : listener (listenerIn) {}
1803
1804 ~ComponentRestarter() noexcept override
1805 {
1806 cancelPendingUpdate();
1807 }
1808
1809 void restart (int32 newFlags)
1810 {
1811 if (newFlags == 0)
1812 return;
1813
1814 flags.fetch_or (newFlags);
1815
1816 if (MessageManager::getInstance()->isThisTheMessageThread())
1817 handleAsyncUpdate();
1818 else
1819 triggerAsyncUpdate();
1820 }
1821
1822private:
1823 void handleAsyncUpdate() override
1824 {
1825 listener.restartComponentOnMessageThread (flags.exchange (0));
1826 }
1827
1828 Listener& listener;
1829 std::atomic<int32> flags { 0 };
1830};
1831
1832JUCE_END_NO_SANITIZE
1833
1834} // namespace juce
1835
1836#endif
T accumulate(T... args)
T addressof(T... args)
T all_of(T... args)
T back(T... args)
T begin(T... args)
T call_once(T... args)
The basic interface of all interfaces.
Definition funknown.h:375
virtual tresult PLUGIN_API queryInterface(const TUID _iid, void **obj)=0
Query for a pointer to the specified interface.
Class factory that any plug-in defines for creating class instances: IPluginFactory.
virtual tresult PLUGIN_API createInstance(FIDString cid, FIDString _iid, void **obj)=0
Create a new class instance.
UTF-16 string with fixed buffer size.
Definition ustring.h:82
UTF-16 string class without buffer management.
Definition ustring.h:29
UString & fromAscii(const char *src, int32 srcSize=-1)
Copy from ASCII string (srcSize is in code unit (count of char16)).
Definition ustring.cpp:132
UString & assign(const char16 *src, int32 srcSize=-1)
Copy from UTF-16 buffer (srcSize is in code unit (count of char16)).
Definition ustring.cpp:110
Basic Bus object.
Definition vstbus.h:58
Audio processing interface: Vst::IAudioProcessor.
virtual tresult PLUGIN_API getBusArrangement(BusDirection dir, int32 index, SpeakerArrangement &arr)=0
Gets the bus arrangement for a given direction (input/output) and index.
List of events to process: Vst::IEventList.
Definition ivstevents.h:197
virtual tresult PLUGIN_API addEvent(Event &e)=0
Adds a new event.
virtual int32 PLUGIN_API getEventCount()=0
Returns the count of events.
virtual tresult PLUGIN_API getEvent(int32 index, Event &e)=0
Gets parameter by index.
MIDI Mapping interface: Vst::IMidiMapping.
virtual tresult PLUGIN_API getMidiControllerAssignment(int32 busIndex, int16 channel, CtrlNumber midiControllerNumber, ParamID &id)=0
Gets an (preferred) associated ParamID for a given Input Event Bus index, channel and MIDI Controller...
static AudioChannelSet JUCE_CALLTYPE disabled()
Creates a zero-channel set which can be used to indicate that a bus is disabled.
static AudioChannelSet JUCE_CALLTYPE mono()
Creates a one-channel mono set (centre).
ChannelType
Represents different audio channel types.
@ ambisonicACN54
Seventh-order ambisonic channel number 54.
@ wideRight
Wide Right channel.
@ topFrontRight
Top Front Right channel.
@ ambisonicACN2
First-order ambisonic channel number 2.
@ topFrontLeft
Top Front Left channel.
@ ambisonicACN25
Fifth-order ambisonic channel number 25.
@ ambisonicACN48
Sixth-order ambisonic channel number 48.
@ ambisonicACN28
Fifth-order ambisonic channel number 28.
@ ambisonicACN59
Seventh-order ambisonic channel number 59.
@ ambisonicACN13
Third-order ambisonic channel number 13.
@ ambisonicACN8
Second-order ambisonic channel number 8.
@ ambisonicACN4
Second-order ambisonic channel number 4.
@ topRearLeft
Top Rear Left channel.
@ ambisonicACN15
Third-order ambisonic channel number 15.
@ ambisonicACN38
Sixth-order ambisonic channel number 38.
@ topSideLeft
Lts (AAX), Tsl (VST), Ltm (AU) channel for Dolby Atmos.
@ ambisonicACN30
Fifth-order ambisonic channel number 30.
@ ambisonicACN61
Seventh-order ambisonic channel number 61.
@ unknown
Unknown channel type.
@ ambisonicACN50
Seventh-order ambisonic channel number 50.
@ proximityRight
Proximity Right (Pr)
@ ambisonicACN19
Fourth-order ambisonic channel number 19.
@ ambisonicACN18
Fourth-order ambisonic channel number 18.
@ bottomRearCentre
Bottom Rear Center (Brc)
@ ambisonicACN27
Fifth-order ambisonic channel number 27.
@ ambisonicACN46
Sixth-order ambisonic channel number 46.
@ ambisonicACN57
Seventh-order ambisonic channel number 57.
@ ambisonicACN49
Seventh-order ambisonic channel number 49.
@ ambisonicACN62
Seventh-order ambisonic channel number 62.
@ ambisonicACN53
Seventh-order ambisonic channel number 53.
@ ambisonicACN51
Seventh-order ambisonic channel number 51.
@ ambisonicACN40
Sixth-order ambisonic channel number 40.
@ ambisonicACN21
Fourth-order ambisonic channel number 21.
@ bottomRearRight
Bottom Rear Right (Brr)
@ ambisonicACN26
Fifth-order ambisonic channel number 26.
@ ambisonicACN22
Fourth-order ambisonic channel number 22.
@ ambisonicACN12
Third-order ambisonic channel number 12.
@ bottomRearLeft
Bottom Rear Left (Brl)
@ ambisonicACN24
Fourth-order ambisonic channel number 24.
@ topSideRight
Rts (AAX), Tsr (VST), Rtm (AU) channel for Dolby Atmos.
@ ambisonicACN36
Sixth-order ambisonic channel number 36.
@ ambisonicACN1
First-order ambisonic channel number 1.
@ ambisonicACN32
Fifth-order ambisonic channel number 32.
@ ambisonicACN52
Seventh-order ambisonic channel number 52.
@ ambisonicACN41
Sixth-order ambisonic channel number 41.
@ rightSurroundRear
Rsr (AAX), Rcs (VST), Rrs (AU) channel.
@ rightSurroundSide
Rss (AXX), Side right "Sr" (VST), Right Centre "Rc" (AU) channel.
@ ambisonicACN29
Fifth-order ambisonic channel number 29.
@ ambisonicACN3
First-order ambisonic channel number 3.
@ ambisonicACN31
Fifth-order ambisonic channel number 31.
@ bottomFrontRight
Bottom Front Right (Bfr)
@ ambisonicACN6
Second-order ambisonic channel number 6.
@ ambisonicACN45
Sixth-order ambisonic channel number 45.
@ wideLeft
Wide Left channel.
@ ambisonicACN43
Sixth-order ambisonic channel number 43.
@ ambisonicACN17
Fourth-order ambisonic channel number 17.
@ proximityLeft
Proximity Left (Pl)
@ ambisonicACN35
Fifth-order ambisonic channel number 35.
@ ambisonicACN37
Sixth-order ambisonic channel number 37.
@ ambisonicACN20
Fourth-order ambisonic channel number 20.
@ ambisonicACN16
Fourth-order ambisonic channel number 16.
@ ambisonicACN44
Sixth-order ambisonic channel number 44.
@ ambisonicACN55
Seventh-order ambisonic channel number 55.
@ ambisonicACN0
Zero-th ambisonic channel number 0.
@ bottomFrontCentre
Bottom Front Centre (Bfc)
@ ambisonicACN10
Third-order ambisonic channel number 10.
@ topRearCentre
Top Rear Centre channel.
@ ambisonicACN14
Third-order ambisonic channel number 14.
@ ambisonicACN60
Seventh-order ambisonic channel number 60.
@ topMiddle
Top Middle channel.
@ topFrontCentre
Top Front Centre channel.
@ ambisonicACN34
Fifth-order ambisonic channel number 34.
@ topRearRight
Top Rear Right channel.
@ LFE2
Second LFE channel.
@ rightCentre
Rc (AAX/VST), Rc used as Rss in AU for most layouts.
@ leftCentre
Lc (AAX/VST), Lc used as Lss in AU for most layouts.
@ ambisonicACN58
Seventh-order ambisonic channel number 58.
@ bottomSideRight
Bottom Side Right (Bsr)
@ ambisonicACN39
Sixth-order ambisonic channel number 39.
@ ambisonicACN5
Second-order ambisonic channel number 5.
@ ambisonicACN23
Fourth-order ambisonic channel number 23.
@ ambisonicACN11
Third-order ambisonic channel number 11.
@ leftSurroundSide
Lss (AXX), Side Left "Sl" (VST), Left Centre "LC" (AU) channel.
@ ambisonicACN56
Seventh-order ambisonic channel number 56.
@ bottomSideLeft
Bottom Side Left (Bsl)
@ ambisonicACN7
Second-order ambisonic channel number 7.
@ ambisonicACN33
Fifth-order ambisonic channel number 33.
@ discreteChannel0
Non-typed individual channels are indexed upwards from this value.
@ ambisonicACN47
Sixth-order ambisonic channel number 47.
@ bottomFrontLeft
Bottom Front Left (Bfl)
@ ambisonicACN42
Sixth-order ambisonic channel number 42.
@ leftSurroundRear
Lsr (AAX), Lcs (VST), Rls (AU) channel.
@ ambisonicACN63
Seventh-order ambisonic channel number 63.
@ ambisonicACN9
Third-order ambisonic channel number 9.
static AudioChannelSet JUCE_CALLTYPE channelSetWithChannels(const Array< ChannelType > &)
Creates a channel set for a list of channel types.
static AudioChannelSet JUCE_CALLTYPE ambisonic(int order=1)
Creates a set for ACN, SN3D normalised ambisonic surround setups with a given order.
Wraps a pointer to a null-terminated UTF-16 character string, and provides various methods to operate...
Wraps a pointer to a null-terminated UTF-8 character string, and provides various methods to operate ...
The JUCE String class!
Definition juce_String.h:53
T data(T... args)
T distance(T... args)
T end(T... args)
T find_if(T... args)
T for_each(T... args)
const Speaker kSpeakerACN21
Ambisonic ACN 21.
Definition vstspeaker.h:84
const Speaker kSpeakerPr
Proximity Right (Pr)
Definition vstspeaker.h:99
const Speaker kSpeakerCs
Center of Surround (Cs) - Back Center - Surround (S)
Definition vstspeaker.h:50
const Speaker kSpeakerLfe
Subbass (Lfe)
Definition vstspeaker.h:44
const Speaker kSpeakerTsl
Top Side Left (Tsl)
Definition vstspeaker.h:89
const Speaker kSpeakerACN24
Ambisonic ACN 24.
Definition vstspeaker.h:87
const Speaker kSpeakerACN0
Ambisonic ACN 0.
Definition vstspeaker.h:63
const Speaker kSpeakerR
Right (R)
Definition vstspeaker.h:42
const Speaker kSpeakerBfr
Bottom Front Right (Bfr)
Definition vstspeaker.h:96
const Speaker kSpeakerRcs
Right of Center Surround (Rcs) - Back Right Center.
Definition vstspeaker.h:92
const Speaker kSpeakerACN2
Ambisonic ACN 2.
Definition vstspeaker.h:65
const Speaker kSpeakerACN1
Ambisonic ACN 1.
Definition vstspeaker.h:64
const Speaker kSpeakerTrc
Top Rear/Back Center (Trc)
Definition vstspeaker.h:58
const Speaker kSpeakerACN18
Ambisonic ACN 18.
Definition vstspeaker.h:81
const Speaker kSpeakerACN20
Ambisonic ACN 20.
Definition vstspeaker.h:83
const Speaker kSpeakerACN14
Ambisonic ACN 14.
Definition vstspeaker.h:77
const Speaker kSpeakerRc
Right of Center (Rc) - Front Right Center.
Definition vstspeaker.h:48
const Speaker kSpeakerBrr
Bottom Rear Right (Brr)
Definition vstspeaker.h:105
const Speaker kSpeakerM
Mono (M)
Definition vstspeaker.h:61
const Speaker kSpeakerL
Speaker Definitions.
Definition vstspeaker.h:41
const Speaker kSpeakerACN8
Ambisonic ACN 8.
Definition vstspeaker.h:71
const Speaker kSpeakerSl
Side Left (Sl)
Definition vstspeaker.h:51
const Speaker kSpeakerLs
Left Surround (Ls)
Definition vstspeaker.h:45
const Speaker kSpeakerBrc
Bottom Rear Center (Brc)
Definition vstspeaker.h:104
const Speaker kSpeakerACN11
Ambisonic ACN 11.
Definition vstspeaker.h:74
const SpeakerArrangement kEmpty
Speaker Arrangement Definitions.
Definition vstspeaker.h:118
const Speaker kSpeakerACN13
Ambisonic ACN 13.
Definition vstspeaker.h:76
const Speaker kSpeakerTsr
Top Side Right (Tsr)
Definition vstspeaker.h:90
const Speaker kSpeakerACN4
Ambisonic ACN 4.
Definition vstspeaker.h:67
const Speaker kSpeakerSr
Side Right (Sr)
Definition vstspeaker.h:52
const Speaker kSpeakerACN23
Ambisonic ACN 23.
Definition vstspeaker.h:86
const Speaker kSpeakerLcs
Left of Center Surround (Lcs) - Back Left Center.
Definition vstspeaker.h:91
const Speaker kSpeakerBsl
Bottom Side Left (Bsl)
Definition vstspeaker.h:101
const Speaker kSpeakerACN5
Ambisonic ACN 5.
Definition vstspeaker.h:68
const Speaker kSpeakerTfr
Top Front Right (Tfr)
Definition vstspeaker.h:56
const Speaker kSpeakerTrl
Top Rear/Back Left (Trl)
Definition vstspeaker.h:57
const Speaker kSpeakerACN6
Ambisonic ACN 6.
Definition vstspeaker.h:69
const Speaker kSpeakerACN16
Ambisonic ACN 16.
Definition vstspeaker.h:79
const Speaker kSpeakerACN19
Ambisonic ACN 19.
Definition vstspeaker.h:82
const Speaker kSpeakerLfe2
Subbass 2 (Lfe2)
Definition vstspeaker.h:60
const Speaker kSpeakerACN17
Ambisonic ACN 17.
Definition vstspeaker.h:80
int32 getChannelCount(SpeakerArrangement arr)
Returns number of channels used in speaker arrangement.
Definition vstspeaker.h:630
const Speaker kSpeakerRs
Right Surround (Rs)
Definition vstspeaker.h:46
const Speaker kSpeakerC
Center (C)
Definition vstspeaker.h:43
const Speaker kSpeakerBrl
Bottom Rear Left (Brl)
Definition vstspeaker.h:103
const Speaker kSpeakerBfc
Bottom Front Center (Bfc)
Definition vstspeaker.h:95
const Speaker kSpeakerACN3
Ambisonic ACN 3.
Definition vstspeaker.h:66
const Speaker kSpeakerACN22
Ambisonic ACN 22.
Definition vstspeaker.h:85
const Speaker kSpeakerBsr
Bottom Side Right (Bsr)
Definition vstspeaker.h:102
const Speaker kSpeakerACN12
Ambisonic ACN 12.
Definition vstspeaker.h:75
const Speaker kSpeakerACN15
Ambisonic ACN 15.
Definition vstspeaker.h:78
const Speaker kSpeakerACN7
Ambisonic ACN 7.
Definition vstspeaker.h:70
const Speaker kSpeakerACN9
Ambisonic ACN 9.
Definition vstspeaker.h:72
const Speaker kSpeakerLc
Left of Center (Lc) - Front Left Center.
Definition vstspeaker.h:47
const Speaker kSpeakerTfc
Top Front Center (Tfc)
Definition vstspeaker.h:55
const Speaker kSpeakerTfl
Top Front Left (Tfl)
Definition vstspeaker.h:54
const Speaker kSpeakerTc
Top Center Over-head, Top Middle (Tc)
Definition vstspeaker.h:53
const Speaker kSpeakerBfl
Bottom Front Left (Bfl)
Definition vstspeaker.h:94
const Speaker kSpeakerTrr
Top Rear/Back Right (Trr)
Definition vstspeaker.h:59
const Speaker kSpeakerPl
Proximity Left (Pl)
Definition vstspeaker.h:98
const Speaker kSpeakerACN10
Ambisonic ACN 10.
Definition vstspeaker.h:73
const FIDString kPlatformTypeNSView
The parent parameter in IPlugView::attached() is a NSView pointer.
Definition iplugview.h:70
const FIDString kPlatformTypeX11EmbedWindowID
The parent parameter in IPlugView::attached() is a X11 Window supporting XEmbed.
Definition iplugview.h:79
const FIDString kPlatformTypeHWND
The parent parameter in IPlugView::attached() is a HWND handle.
Definition iplugview.h:62
#define JUCE_BEGIN_NO_SANITIZE(warnings)
Disable sanitizers for a range of functions.
#define jassert(expression)
Platform-independent assertion macro.
#define JUCE_DECLARE_NON_MOVEABLE(className)
This is a shorthand macro for deleting a class's move constructor and move assignment operator.
#define JUCE_DECLARE_NON_COPYABLE(className)
This is a shorthand macro for deleting a class's copy constructor and copy assignment operator.
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...
#define jassertfalse
This will always cause an assertion failure.
auto & get(ProcessorChain< Processors... > &chain) noexcept
Non-member equivalent of ProcessorChain::get which avoids awkward member template syntax.
typedef int
T max(T... args)
T memcmp(T... args)
T move(T... args)
SMTG_CONSTEXPR const CString kMono
used for Mono only plug-in [optional]
SMTG_CONSTEXPR const CString kStereo
used for Stereo only plug-in [optional]
Speaker Arrangement Definitions (SpeakerArrangement)
Definition vstspeaker.h:112
const SpeakerArrangement k71_6
L R C Lfe Ls Rs Sl Sr Tfl Tfr Trl Trr Tsl Tsr.
Definition vstspeaker.h:291
const SpeakerArrangement k51
L R C Lfe Ls Rs.
Definition vstspeaker.h:151
const SpeakerArrangement k70Cine
L R C Ls Rs Lc Rc.
Definition vstspeaker.h:161
const SpeakerArrangement k71Cine
L R C Lfe Ls Rs Lc Rc.
Definition vstspeaker.h:163
const SpeakerArrangement k91_4
L R C Lfe Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr.
Definition vstspeaker.h:299
const SpeakerArrangement k70Music
L R C Ls Rs Sl Sr.
Definition vstspeaker.h:166
const SpeakerArrangement k40Cine
L R C S.
Definition vstspeaker.h:141
const SpeakerArrangement k61Cine
L R C Lfe Ls Rs Cs.
Definition vstspeaker.h:155
const SpeakerArrangement k60Music
L R Ls Rs Sl Sr.
Definition vstspeaker.h:157
const SpeakerArrangement kAmbi7thOrderACN
Seventh-Order with Ambisonic Channel Number (ACN) ordering and SN3D normalization (64 channels)
Definition vstspeaker.h:209
const SpeakerArrangement kAmbi5thOrderACN
Fifth-Order with Ambisonic Channel Number (ACN) ordering and SN3D normalization (36 channels)
Definition vstspeaker.h:205
const SpeakerArrangement k70_2
L R C Ls Rs Sl Sr Tsl Tsr.
Definition vstspeaker.h:263
const SpeakerArrangement k90_6
L R C Lfe Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr Tsl Tsr.
Definition vstspeaker.h:302
const SpeakerArrangement kAmbi6thOrderACN
Sixth-Order with Ambisonic Channel Number (ACN) ordering and SN3D normalization (49 channels)
Definition vstspeaker.h:207
const SpeakerArrangement k71_4
L R C Lfe Ls Rs Sl Sr Tfl Tfr Trl Trr.
Definition vstspeaker.h:282
const SpeakerArrangement k40Music
L R Ls Rs.
Definition vstspeaker.h:145
const SpeakerArrangement k30Music
L R S.
Definition vstspeaker.h:137
const SpeakerArrangement k70_6
L R C Ls Rs Sl Sr Tfl Tfr Trl Trr Tsl Tsr.
Definition vstspeaker.h:286
const SpeakerArrangement k71Music
L R C Lfe Ls Rs Sl Sr.
Definition vstspeaker.h:168
const SpeakerArrangement k60Cine
L R C Ls Rs Cs.
Definition vstspeaker.h:153
const SpeakerArrangement k90_4
L R C Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr.
Definition vstspeaker.h:294
const SpeakerArrangement k50
L R C Ls Rs.
Definition vstspeaker.h:149
const SpeakerArrangement k70_4
L R C Ls Rs Sl Sr Tfl Tfr Trl Trr.
Definition vstspeaker.h:278
const SpeakerArrangement k71_2
L R C Lfe Ls Rs Sl Sr Tsl Tsr.
Definition vstspeaker.h:267
const SpeakerArrangement k61Music
L R Lfe Ls Rs Sl Sr.
Definition vstspeaker.h:159
const SpeakerArrangement k30Cine
L R C.
Definition vstspeaker.h:133
const SpeakerArrangement k91_6
L R C Lfe Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr Tsl Tsr.
Definition vstspeaker.h:307
All VST specific interfaces are located in Vst namespace.
@ kOutput
output bus
@ kInput
input bus
uint8 controlNumber
see enum ControllerNumbers [0, 255]
Definition ivstevents.h:131
uint64 Speaker
Bit for one speaker.
Definition vsttypes.h:105
int8 value
value of Controller [0, 127]
Definition ivstevents.h:133
uint32 ParamID
parameter identifier
Definition vsttypes.h:81
TChar String128[128]
128 character UTF-16 string
Definition vsttypes.h:69
char16 TChar
UTF-16 character.
Definition vsttypes.h:68
int8 value2
[0, 127] used for pitch bend (kPitchBend) and polyPressure (kCtrlPolyPressure)
Definition ivstevents.h:134
double ParamValue
parameter value type
Definition vsttypes.h:80
int16 CtrlNumber
MIDI controller number (see ControllerNumbers for allowed values)
Definition vsttypes.h:83
int8 channel
channel index in event bus [0, 15]
Definition ivstevents.h:132
uint64 SpeakerArrangement
Bitset of speakers.
Definition vsttypes.h:104
@ kPitchBend
Pitch Bend Change.
@ kCtrlProgramChange
Program Change (use LegacyMIDICCOutEvent.value only)
@ kCountCtrlNumber
Count of Controller Number.
@ kCtrlPolyPressure
Polyphonic Key Pressure (use LegacyMIDICCOutEvent.value for pitch and LegacyMIDICCOutEvent....
@ kCtrlQuarterFrame
Quarter Frame ((use LegacyMIDICCOutEvent.value only)
@ kAfterTouch
After Touch (associated to Channel Pressure)
Legacy MIDI CC Out event specific data.
Definition ivstevents.h:130
JUCE Namespace.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
const DirectoryEntry & operator*(const DirectoryEntry &e) noexcept
A convenience operator so that the expression *it++ works correctly when it is an instance of RangedD...
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Constrains a value to keep it within a given range.
signed int int32
A platform-independent 32-bit signed integer type.
constexpr int countNumberOfBits(uint32 n) noexcept
Returns the number of bits in a 32-bit integer.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
int roundToInt(const FloatType value) noexcept
Fast floating-point-to-integer conversion.
constexpr int numElementsInArray(Type(&)[N]) noexcept
Handy function for getting the number of elements in a simple const C array.
T push_back(T... args)
T size(T... args)
std::u16string toString(NumberT value)
convert an number to an UTF-16 string
Processing buffers of an audio bus.
int32 numChannels
number of audio channels in bus
uint64 silenceFlags
Bitset of silence state per channel.
Data event specific data.
Definition ivstevents.h:71
uint32 type
type of this data block (see DataTypes)
Definition ivstevents.h:73
@ kMidiSysEx
for MIDI system exclusive message
Definition ivstevents.h:79
const uint8 * bytes
pointer to the data block
Definition ivstevents.h:74
uint32 size
size in bytes of the data block bytes
Definition ivstevents.h:72
EventStructure representing a single Event of different types associated to a specific event (kEvent)...
Definition ivstevents.h:143
int32 sampleOffset
sample frames related to the current block start sample position
Definition ivstevents.h:145
@ kScaleEvent
is ScaleEvent
Definition ivstevents.h:168
@ kNoteExpressionValueEvent
is NoteExpressionValueEvent
Definition ivstevents.h:165
@ kPolyPressureEvent
is PolyPressureEvent
Definition ivstevents.h:164
@ kNoteExpressionTextEvent
is NoteExpressionTextEvent
Definition ivstevents.h:166
@ kNoteOffEvent
is NoteOffEvent
Definition ivstevents.h:162
@ kChordEvent
is ChordEvent
Definition ivstevents.h:167
@ kNoteOnEvent
is NoteOnEvent
Definition ivstevents.h:161
@ kLegacyMIDICCOutEvent
is LegacyMIDICCOutEvent
Definition ivstevents.h:169
@ kDataEvent
is DataEvent
Definition ivstevents.h:163
uint16 type
a value from EventTypes
Definition ivstevents.h:172
Any data needed in audio processing.
T swap(T... args)
sync
typedef size_t