forked from Celemony/ARA_API
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ARAInterface.h
3653 lines (3136 loc) · 213 KB
/
ARAInterface.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//------------------------------------------------------------------------------
//! \file ARAInterface.h
//! definition of the ARA application programming interface
//! \project ARA API Specification
//! \copyright Copyright (c) 2012-2021, Celemony Software GmbH, All Rights Reserved.
//! Developed in cooperation with PreSonus Software Ltd.
//! \license Licensed under the Apache License, Version 2.0 (the "License");
//! you may not use this file except in compliance with the License.
//! You may obtain a copy of the License at
//!
//! http://www.apache.org/licenses/LICENSE-2.0
//!
//! Unless required by applicable law or agreed to in writing, software
//! distributed under the License is distributed on an "AS IS" BASIS,
//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//! See the License for the specific language governing permissions and
//! limitations under the License.
//------------------------------------------------------------------------------
/***************************************************************************************************/
// IMPORTANT:
// Please read ARA_API.pdf for general documentation before studying this header!
/***************************************************************************************************/
#ifndef ARAInterface_h
#define ARAInterface_h
/***************************************************************************************************/
#if defined(__clang__)
#pragma mark General configuration
#endif
/***************************************************************************************************/
/***************************************************************************************************/
// Supported architectures
#if !(defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86))
#if defined(__arm64__) || defined(__arm64e__) || defined(_M_ARM64)
#if defined(_MSC_VER)
#pragma message("warning: ARM support is still work-in-progress and subject to change in potentially incompatible ways")
#else
#if defined(__GNUC__)
_Pragma ("GCC diagnostic push")
_Pragma ("GCC diagnostic ignored \"-Wpedantic\"")
#endif
#warning "ARM support is still work-in-progress and subject to change in potentially incompatible ways"
#if defined(__GNUC__)
_Pragma ("GCC diagnostic pop")
#endif
#endif
#else
#error "unsupported architecture"
#endif
#endif
/***************************************************************************************************/
// C99 standard includes for the basic data types
#include <stddef.h>
#include <stdint.h>
/***************************************************************************************************/
// Auxiliary defines for Doxygen code generation, must evaluate to 0 for actual code compilation
// Enable this when building Doxygen documentation
#if !defined(ARA_DOXYGEN_BUILD)
#define ARA_DOXYGEN_BUILD 0
#endif
/***************************************************************************************************/
// Various configurations/decorations to ensure binary compatibility.
#if defined(__cplusplus) && !(ARA_DOXYGEN_BUILD)
namespace ARA
{
extern "C"
{
#endif
// Ensure binary compatibility across compilers by explicitly defining binary data layout.
// To prevent any alignment/padding settings from the surrounding code to modify the ARA data layout,
// we need to explicitly define the layout here. Ideally, we would stick with the C standard
// alignment/padding (struct alignment defined by largest member, each member aligned by its size),
// but at the time when ARA 1 was developed there was no way to achieve this in code.
// As a workaround, ARA started using 1-byte packing. However, this causes some members in some of
// the ARA structs to be not naturally aligned on 64 bit systems. But moreover, this also affects
// the possible alignment of all ARA structs in some compilers. Thus developers that directly use
// the C API must carefully align any data that they pass across the API boundary in order to avoid
// performance penalties. When using the ARA library C++ dispatch code, the SizedStruct<> template
// which is used as central low-level wrapper for any data crossing the API takes care of this issue.
#if defined(_MSC_VER) || defined(__GNUC__)
#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
// This is for historical reason - current MSVC defaults are 8 on x86 and 16 on x64.
#pragma pack(push, 1)
#elif defined(__arm64__) || defined(__arm64e__) || defined(_M_ARM64)
// MSVC default for ARM64 is 8, this also fits the standard packing by member size for
// the vast majority of the structs in the ARA API on 64 bit processors.
#pragma pack(push, 8)
#else
#error "struct packing and alignment not yet defined for this processor"
#endif
#else
#error "struct packing and alignment not yet defined for this compiler"
#endif
// Override any custom calling conventions, stick with the C standard calling convention.
#if defined(_MSC_VER)
#define ARA_CALL __cdecl
#else
#define ARA_CALL
#endif
/***************************************************************************************************/
//! @addtogroup API_generations API Generations
// Macros to mark API added or deprecated as the API evolves - see ARAAPIGeneration.
//! @{
// Internal macro to trigger deprecation warnings (not fully supported by all compilers).
#if defined(__cplusplus) && defined(__has_cpp_attribute)
#if __has_cpp_attribute(deprecated)
// C++14 standard
#define ARA_WARN_DEPRECATED(generation) [[deprecated("deprecated as of kARAAPIGeneration_"#generation)]]
#endif
#endif
#if !defined(ARA_WARN_DEPRECATED) && defined(__GNUC__)
// Vendor-specific: gcc & clang.
#define ARA_WARN_DEPRECATED(generation) __attribute__((deprecated))
#endif
#if !defined(ARA_WARN_DEPRECATED) && defined(_MSC_VER)
// Vendor-specific: Visual Studio.
#define ARA_WARN_DEPRECATED(generation) __declspec(deprecated("deprecated as of kARAAPIGeneration_"#generation))
#endif
//! Markup for outdated API that should no longer be used in future development, but can still
//! be supported for backwards compatibility with older plug-ins/hosts if desired. \br
//! By defining ARA_ENABLE_DEPRECATION_WARNINGS as non-zero value it is possible to get deprecation
//! warnings in the most common compilers, for inspecting deprecated API usage in a given project.
//! These warnings are disabled by default in order to not interfere with code that supports older APIs.
#define ARA_DEPRECATED(generation)
#if defined(ARA_ENABLE_DEPRECATION_WARNINGS) && (ARA_ENABLE_DEPRECATION_WARNINGS)
#if !defined(ARA_WARN_DEPRECATED)
#warning ARA_ENABLE_DEPRECATION_WARNINGS is not supported for this compiler - no deprecation warnings will be shown!
#endif
#undef ARA_DEPRECATED
#define ARA_DEPRECATED(generation) ARA_WARN_DEPRECATED(generation)
#endif
//! Markup for struct elements which were added in later revisions of the API and may be omitted
//! from the struct when dealing with older plug-ins/hosts.
#define ARA_ADDENDUM(generation)
//! Markup for draft API that is still under active development and not yet properly versioned -
//! when using those struct elements, host and plug-in must agree on a specific draft header version! \br
//! All uses of this macro will be replaced by ARA_ADDENDUM() upon final release.
//! To quickly find all places in your project that use draft API, it's possible to temporarily
//! redefine ARA_DRAFT to ARA_WARN_DEPRECATED(...).
#define ARA_DRAFT ARA_ADDENDUM(2_X_Draft)
// use this alternate definition to trigger a "deprecation" warning for every location draft API is used
//#undef ARA_DRAFT
//#define ARA_DRAFT ARA_WARN_DEPRECATED(2_X_Draft)
//! @}
/***************************************************************************************************/
#if defined(__clang__)
#pragma mark Basic constants and data types
#endif
//! @defgroup Basic_Types Basic Types
//! Pre-defined types to ensure binary compatibility between plug-in and host.
//! These types must be used when crossing the API boundary, but intermediate types can be used internally.
//! For example, you can use your own struct representing color, but when defining color for ARA operations
//! your internal color struct must be converted to ARAColor.
//! @{
/***************************************************************************************************/
/***************************************************************************************************/
//! @defgroup Fixed-size_integers Fixed-size Integers
//! ARA defines platform-independent signed integers with fixed size of 32 or 64 bits
//! and for a pointer-sized signed integer.
//! @{
//! Byte: 8 bits wide unsigned integer.
typedef uint8_t ARAByte;
//! 32 bits wide signed integer.
typedef int32_t ARAInt32;
//! 64 bits wide signed integer.
typedef int64_t ARAInt64;
//! Pointer-wide size value for ARA structs.
typedef size_t ARASize;
//! @}
/***************************************************************************************************/
//! @defgroup Boolean_values Boolean Values
//! Since Microsoft still doesn't fully support C99 and fails to provide <stdbool.h>,
//! we need to roll our own. On the other hand this ensures a fixed size of 32 bits, too.
//! 32 bits were chosen so that ARABool is consistent with the other enum-like data types such as
//! ARAContentType. Since ARABool is only used in temporary structs that are valid only for the
//! duration of a call and likely passed in a register in most cases, there's no point in trying
//! to optimize for size by using 8 bit boolean types.
//! Note that in order to avoid conversion warnings in Visual Studio, you should not directly cast
//! bool to ARABool or vice versa, but instead use a ternary operator or a comparison like this:
//! \code{.c}
//! araBool = (cppBool) ? kARATrue : kARAFalse;
//! cppBool = (araBool != kARAFalse);
//! \endcode
//! Providing conversion operators for ARABool for C++ that handle this automatically is alas no
//! viable option, because ARABool is only a typedef so this would lead to side-effects for all
//! conversions from the integer type that ARABool is defined upon.
//! @{
//! Platform independent 32-bit boolean value.
typedef ARAInt32 ARABool;
#if defined(__cplusplus)
//! "true" value for ARABool.
constexpr ARABool kARATrue { 1 };
//! "false" value for ARABool.
constexpr ARABool kARAFalse { 0 };
#else
#define kARATrue ((ARABool)1)
#define kARAFalse ((ARABool)0)
#endif
//! @}
/***************************************************************************************************/
//! @defgroup Enums Enums
//! ARA enums can either be used to represent distinct enumerations, or to
//! declare C-compatible constant integer flags that can be or'd together as bit masks.
//! To ensure binary compatibility between plug-in and host, the underlying type
//! of ARA enums is always ARAInt32.
//! @{
//! Define a 32-bit ARA enum type.
//! The actual enum declaration is encapsulated in a macro to allow for adjusting it between
//! C++, C and Doxygen builds.
#if ARA_DOXYGEN_BUILD
#define ARA_32_BIT_ENUM(name) \
enum name : ARAInt32
#elif defined(__cplusplus) && ((__cplusplus >= 201103L) || (defined(_MSC_VER) && (_MSC_VER >= 1900)))
#define ARA_32_BIT_ENUM(name) \
ARAInt32 name; \
enum : ARAInt32
#else
#define ARA_32_BIT_ENUM(name) \
ARAInt32 name; \
enum
#endif
//! @}
/***************************************************************************************************/
//! @defgroup Strings Strings
//! User-readable texts are stored as UTF-8 encoded unicode strings.
//! It's not defined if and how the string is normalized - if either side has requirements regarding
//! normalization, it needs to apply these after reading the string from the other side.
//! Unicode rules apply regarding normalization, comparison etc.
//! Both hosts and plug-ins are required to support at least all ISO/IEC 8859-1 based characters
//! (from U+0020 up to U+007E and from U+00A0 up to U+00FF) in their text display rendering.
//! @{
//! A single character.
typedef char ARAUtf8Char;
//! A string, 0-terminated.
typedef const ARAUtf8Char * ARAUtf8String;
//! @}
/***************************************************************************************************/
//! @defgroup Common_time-related_data_types Common Time-Related Data Types
//! Some basic data types used in several contexts.
//! @{
//! A point in time in seconds.
typedef double ARATimePosition;
//! A duration of time in seconds - the start of the duration is part of the interval, the end is not.
typedef double ARATimeDuration;
//! Integer sample index, always related to a particular sample rate defined by the context it is used in.
typedef ARAInt64 ARASamplePosition;
//! Integer sample count, always related to a particular sample rate defined by the context this is used in.
typedef ARAInt64 ARASampleCount;
//! A position in musical time measured in quarter notes.
typedef double ARAQuarterPosition;
//! A duration in musical time measured in quarter notes - the start of the duration is part of the interval, the end is not.
typedef double ARAQuarterDuration;
//! @}
/***************************************************************************************************/
//! @defgroup Sampled_audio_data Sampled Audio Data
//! The audio samples are encoded using these format descriptions.
//! The data alignment and byte order always matches the machine's native layout.
//! @{
//! Specified in Hz.
typedef double ARASampleRate;
//! In the current version of ARA, no spatial positioning of the channels is defined.
typedef ARAInt32 ARAChannelCount;
//! @}
/***************************************************************************************************/
//! @defgroup Color Color
//! ARA color representation.
//! @{
//! R/G/B color, values range from 0.0f to 1.0f.
//! Does not include transparency because it must not depend on the background its drawn upon
//! in order to be equally represented in both the host and plug-in UI - any transparency on
//! either side must be converted depending on internal drawing before/after the ARA calls.
ARA_ADDENDUM(2_0_Draft) typedef struct ARAColor
{
float r; //!< red
float g; //!< green
float b; //!< blue
} ARAColor;
//! @}
/***************************************************************************************************/
//! @defgroup Object_References Object References
//! ARA uses pointer-sized unique identifiers to reference objects at runtime -
//! typical C++-based implementations will use the this-pointer as ID.
//! C-style code could do the same, or instead choose to use array indices as ID. \br
//! Those objects that are archived by the host can be persistently identified
//! by an ::ARAPersistentID that the host assigns as a property of the object.
//! @{
//! @name Markup Types
//! Type-safe representations of the opaque refs/host refs.
//! The markup types allow for overloaded custom conversion functions if using C++,
//! or for re-defining the markup types to actual implementations in C like this:
//! \code{.c}
//! #define ARAAudioSourceRefMarkupType MyAudioFileClass
//! #define ARAMusicalContextRefMarkupType MyGlobalTracksClass
//! \endcode
//! ... etc ...
//! @{
//! Plug-in reference markup type identifier. \br\br
//! Examples: \br
//! ::ARAMusicalContextRef \br
//! ::ARARegionSequenceRef \br
//! ::ARAAudioSourceRef \br
//! ::ARAAudioModificationRef \br
//! ::ARAPlaybackRegionRef \br
//! ::ARAContentReaderRef \br
//! ::ARADocumentControllerRef \br
//! ::ARAPlaybackRendererRef \br
//! ::ARAEditorRendererRef \br
//! ::ARAEditorViewRef \br
#define ARA_REF(RefType) struct RefType##MarkupType * RefType
//! Host reference markup type identifier. \br\br
//! Examples: \br
//! ::ARAMusicalContextHostRef \br
//! ::ARARegionSequenceHostRef \br
//! ::ARAAudioSourceHostRef \br
//! ::ARAAudioModificationHostRef \br
//! ::ARAPlaybackRegionHostRef \br
//! ::ARAContentReaderHostRef \br
//! ::ARAAudioAccessControllerHostRef \br
//! ::ARAAudioReaderHostRef \br
//! ::ARAArchivingControllerHostRef \br
//! ::ARAArchiveReaderHostRef \br
//! ::ARAArchiveWriterHostRef \br
//! ::ARAContentAccessControllerHostRef \br
//! ::ARAModelUpdateControllerHostRef \br
//! ::ARAPlaybackControllerHostRef \br
#define ARA_HOST_REF(HostRefType) struct HostRefType##MarkupType * HostRefType
//! @}
//! @name Persistent IDs
//! @{
//! Persistent object reference representation.
//! Persistent IDs are used to encode object references between plug-in and host when dealing
//! with persistency. Contrary to the user-readable ARAUtf8String, ARAPersistentIDs are seven-bit
//! US-ASCII-encoded strings, such as "com.manufacturerDomain.someIdentifier", and can thus be
//! directly compared using strcmp() and its siblings. They can be copied using strcpy() and must
//! always be compared by value, not by address.
typedef const char * ARAPersistentID;
//! @}
//! @}
//! @}
/***************************************************************************************************/
#if defined(__clang__)
#pragma mark Versioning support
#endif
//! @defgroup API_versions API Versions
//! ARA implements two patterns for its ongoing evolution of the API: incremental, fully-backwards
//! compatible additions by appending features to it versioned structs, and major, potentially
//! incompatible updates through its API generations.
//! @{
/***************************************************************************************************/
/***************************************************************************************************/
//! @defgroup API_generations API Generations
//! While purely additive features can be handled through ARA's versioned structs,
//! ARA API generations allow for non-backwards-compatible, fundamental API changes.
//! For hosts that rely on a certain minimum ARA feature set provided by the plug-ins, it also
//! offers a convenient way to filter incompatible plug-ins.
//! Plug-ins on the other hand can use the API generation chosen by the host to optimize their
//! feature set for the given environment, such as disabling potentially costly fallback code
//! required for older hosts when running in a modern host.
//! @{
typedef ARA_32_BIT_ENUM(ARAAPIGeneration)
{
//! private API between Studio One and Melodyne
kARAAPIGeneration_1_0_Draft = 1,
//! supported by Studio One, Cakewalk/SONAR, Samplitude Pro, Mixcraft, Waveform/Tracktion, Melodyne, VocAlign, AutoTune
kARAAPIGeneration_1_0_Final = 2,
//! supported by Studio One, Logic Pro, Cubase/Nuendo, Cakewalk, REAPER, Melodyne, ReVoice Pro, VocAlign, Auto-Align, SpectraLayers
kARAAPIGeneration_2_0_Draft = 3,
//! most developers supporting kARAAPIGeneration_2_0_Draft are already working on updating to kARAAPIGeneration_2_0_Final
kARAAPIGeneration_2_0_Final = 4,
//! reserved for future development
kARAAPIGeneration_2_X_Draft = 5
};
//! @}
/***************************************************************************************************/
//! @defgroup Versioned_structs Versioned Structs
//! In the various interface and data structs used in the ARA API, callback pointers or data fields
//! may be added in later revisions of the current API generation. Each of these extensible structs
//! starts with a structSize data field that describes how much data is actually contained in the
//! given instance of the struct, thus allowing to determine which of the additional features are
//! supported by the other side.
//! All struct members that are later additions will be marked with the macro ARA_ADDENDUM.
//! Members that are not marked as addendum must always be present in the struct.
//! Accordingly, the minimum value of structSize is the size of the struct in the first API revision.
//! When creating such a struct in your code, the maximum value is the size of the struct in the
//! current API revision used at compile time. When parsing a struct received from the other side,
//! the value may be even larger since the other side may use an even later API revision.
//! \br
//! Note that when implementing ARA, it is important not to directly use sizeof() when filling in
//! the structSize values. If you later update to newer API headers, the values of sizeof() will
//! change and your code thus will be broken until you've implemented all additions.
//! Instead, use the ARA_IMPLEMENTED_STRUCT_SIZE macro or similar techniques added in the ARA
//! C++ library dispatcher code, see \ref ARA_Library_Utility_SizedStructs "there".
//! @{
//! Macro that calculates the proper value for the structSize field of a versioned struct based
//! on which features are actually implemented by the code that provides the struct.
//! This may be different from sizeof() whenever features are added in the API, but not yet
//! implemented in the current code base. Only after adding that implementation, the \p memberName
//! parameter provided to ARA_IMPLEMENTED_STRUCT_SIZE should be updated accordingly.
//! \br
//! The ARA library C++ dispatchers implement a similar feature via templates,
//! see ARA::SizedStruct<>.
#if defined(__cplusplus)
#define ARA_IMPLEMENTED_STRUCT_SIZE(StructType, memberName) (offsetof(ARA::StructType, memberName) + sizeof((static_cast<ARA::StructType *> (nullptr))->memberName))
#else
#define ARA_IMPLEMENTED_STRUCT_SIZE(StructType, memberName) (offsetof(StructType, memberName) + sizeof(((StructType *)NULL)->memberName))
#endif
//! Convenience macro to test if a field is present in a given struct.
//! \br
//! The ARA library C++ dispatchers implement a similar feature via templates,
//! see ARA::SizedStructPtr::implements<>().
#if defined(__cplusplus)
#define ARA_IMPLEMENTS_FIELD(pointerToStruct, StructType, memberName) \
((pointerToStruct)->structSize > offsetof(ARA::StructType, memberName))
#else
#define ARA_IMPLEMENTS_FIELD(pointerToStruct, StructType, memberName) \
((pointerToStruct)->structSize > offsetof(StructType, memberName))
#endif
//! @}
//! @}
/***************************************************************************************************/
#if defined(__clang__)
#pragma mark Debugging support
#endif
//! @defgroup Debugging Debugging
//! ARA strictly separates programming errors from runtime error conditions such as missing files,
//! CPU or I/O overloads etc.
//! Runtime errors occur when accessing external data and resources, which is always done on the host
//! side of the ARA API. Accordingly, the host has the responsibility to detect any such errors and
//! to properly communicate the issue to the user. Since ARA leverages existing technologies, host
//! implementations usually already feature proper code for this.
//! With the error reporting done on the host side, plug-ins do not need to know any details about
//! runtime errors - a simple bool to indicate success or failure is sufficient for implementing
//! normal operation or graceful error recovery. Thus, ARA does not need to define error codes for
//! communicating error details across the API.
//! As an example, consider audio data being read from a server across the network - if the connection
//! breaks, the host will recognize the issue and bring up an according user notification. If the
//! plug-in requests the now inaccessible audio data, the host simply flags that an error occurred and
//! the plug-in can either retry later or use silence as fallback data.
//! \br
//! A different kind of errors are programming errors. If either side fails to properly follow the
//! API contract, undefined behavior can occur. Tracking down such bugs from one side only can be
//! difficult and very time consuming, thus ARA strives to aid developers in this process by defining
//! a global assert function that both sides call whenever detecting programming errors related to
//! the ARA API.
//! When debugging (or when running unit tests), either side can provide the code for the assert
//! function, so that no matter what side you're debugging from you can always inject your custom
//! assert handling in order to be able to set proper breakpoints etc.
//! The assert function is only a debug facility: it will usually be disabled on end user systems,
//! and it must never be used for flow control in a shipping product. Instead, each side should
//! implement graceful fallback behavior after asserting the programming error, e.g. by defining a
//! special value for invalid object refs (NULL or -1, depending on the implementation) which will
//! be returned as a placeholder whenever object creation fails due to a programming error on the
//! other side and then filtering this value accordingly whenever objects are referenced.
//! @{
/***************************************************************************************************/
//! Hint about the nature of the programming error.
typedef ARA_32_BIT_ENUM(ARAAssertCategory)
{
//! Not covered by any of the following codes.
kARAAssertUnspecified = 0,
//! Indicate that the caller passed invalid arguments.
kARAAssertInvalidArgument = -1,
//! Indicate that the call is invalid in the current state.
//! e.g. if a document modification is being made without guarding it properly with
//! ARADocumentControllerInterface::beginEditing() and ARADocumentControllerInterface::endEditing()
kARAAssertInvalidState = -2,
//! Indicate that the call cannot be made on the current thread.
kARAAssertInvalidThread = -3
};
//! Global assert function pointer.
//! The assert categories passed to the global assert function are useful both for guiding developers
//! when debugging and for automatic assert evaluation when building unit tests. \br
//! The diagnosis text is intended solely to aid the developer debugging an issue "from the
//! other side"; they must not be presented to the user (or even parsed for flow control).
//! If applicable (i.e. if the category is kARAAssertInvalidArgument), the diagnosis should contain
//! a hint about what problematicArgument actually points to - for example if a struct is too small,
//! you'd pass the pointer to the struct along with a diagnosis message a la:
//! "someExampleInterfacePointer->structSize < kExampleStructMinSize".
//! Creating such appropriate texts automatically can be easily accomplished by custom assert macros. \br
//! Finally, problematicArgument should point to the argument that contains the invalid data, so that
//! the developer on that end can quickly identify the problem. If you can't provide a meaningful
//! address for it, e.g. because the category is kARAAssertInvalidThread, pass NULL here.
typedef void (ARA_CALL * ARAAssertFunction) (ARAAssertCategory category, const void * problematicArgument,
const char * diagnosis);
//! @}
/***************************************************************************************************/
#if defined(__clang__)
#pragma mark Model graph objects
#endif
//! @defgroup ARA_Model_Graph ARA Model Graph
//! @{
/***************************************************************************************************/
/***************************************************************************************************/
//! @defgroup Model_Document Document
//! The document is the root object for a model graph and typically represents a piece of music
//! such as a song or an entire performance.
//! It is bound to a document controller in a 1:1 relationship. The document controller is used to
//! manage the entire graph it contains. Because of the 1:1 relationship, the document is never
//! specified when calling into the document controller.
//! Edits of the document and any of the objects it contains are done in cycles started with
//! ARADocumentControllerInterface::beginEditing() and concluded with
//! ARADocumentControllerInterface::endEditing().
//! This allows plug-ins to deal with any render thread synchronization that may be necessary,
//! as well as postponing any internal updates until the end of the cycle when the ARA graph has
//! its full state available.
//! A document is the root object for persistency and is the owner of any amount of associated
//! audio sources, region sequences and musical contexts.
//! \br
//! Plug-in developers using the C++ ARA Library can use the ARA::PlugIn::Document class.
//! @{
//! Document properties.
//! Note that like all properties, a pointer to this struct is only valid for the duration of the
//! call receiving the pointer - the data must be evaluated/copied inside the call, and the pointer
//! must not be stored anywhere.
typedef struct ARADocumentProperties
{
//! @see_Versioned_Structs
ARASize structSize;
//! User-readable name of the document as displayed in the host.
//! The plug-in must copy the name, the pointer may be only valid for the duration of the call.
//! It may be NULL if the host cannot provide a name for the document.
//! In that case, the host should not make up some dummy name just to satisfy the API, but
//! rather let the plug-in do this if desired - this way it can distinguish between a proper
//! name visible somewhere in the host and a dummy name implicitly derived from other state.
ARAUtf8String name;
} ARADocumentProperties;
// Convenience constant for easy struct validation.
enum { kARADocumentPropertiesMinSize = ARA_IMPLEMENTED_STRUCT_SIZE(ARADocumentProperties, name) };
//! @}
/***************************************************************************************************/
//! @defgroup Model_Musical_Context Musical Context
//! A musical context describes both rhythmical concepts of the music such as bars and beats and
//! their distribution over time, as well as harmonic structures and their distribution over time.
//! A musical context is always owned by one document.
//! Musical contexts are not persistent when storing documents, instead the host re-creates them
//! as needed.
//! \br
//! Plug-in developers using the C++ ARA Library can use the ARA::PlugIn::MusicalContext class.
//! @{
//! Reference to the plug-in side representation of a musical context (opaque to the host).
typedef ARA_REF(ARAMusicalContextRef);
//! Reference to the host side representation of a musical context (opaque to the plug-in).
typedef ARA_HOST_REF(ARAMusicalContextHostRef);
//! Musical context properties.
//! Note that like all properties, a pointer to this struct is only valid for the duration of the
//! call receiving the pointer - the data must be evaluated/copied inside the call, and the pointer
//! must not be stored anywhere.
typedef struct ARAMusicalContextProperties
{
//! @see_Versioned_Structs
ARASize structSize;
//! User-readable name of the musical context as displayed in the host.
//! The plug-in must copy the name, the pointer may be only valid for the duration of the call.
//! It may be NULL if the host cannot provide a name for the musical context (which is typically
//! true for all hosts that only use a single context per document.)
//! In that case, the host should not make up some dummy name just to satisfy the API, but
//! rather let the plug-in do this if desired - this way it can distinguish between a proper
//! name visible somewhere in the host and a dummy name implicitly derived from other state.
ARA_ADDENDUM(2_0_Draft) ARAUtf8String name;
//! Sort order of the musical context in the host.
//! The index must allow for the plug-in to order the musical contexts as shown in the host,
//! but the actual index values are not shown to the user. They can be arbitrary, but must
//! increase strictly monotonically.
ARA_ADDENDUM(2_0_Draft) ARAInt32 orderIndex;
//! Color associated with the musical context in the host.
//! The plug-in must copy the color, the pointer may be only valid for the duration of the call.
//! It may be NULL if the host cannot provide a color for the musical context.
ARA_ADDENDUM(2_0_Draft) const ARAColor * color;
} ARAMusicalContextProperties;
// Convenience constant for easy struct validation.
enum { kARAMusicalContextPropertiesMinSize = ARA_IMPLEMENTED_STRUCT_SIZE(ARAMusicalContextProperties, structSize) };
//! @}
/***************************************************************************************************/
//! @defgroup Model_Region_Sequences Region Sequences (Added In ARA 2.0)
//! Region sequences allow hosts to group playback regions, typically by "tracks" or "lanes" in
//! their arrangement.
//! Each sequence is associated with a musical context, and all regions in a sequence will be adapted
//! to that same context.
//! Further, all regions within a sequence are expected to play back through the same routing (incl.
//! same latency), typically the same "mixer track" or "audio channel".
//! Regions in a sequence can overlap, and such overlapping regions will sound concurrently.
//! A region sequence is always owned by one document, and refers to a musical context.
//! Region sequences are not persistent when storing documents, instead the host re-creates them
//! as needed.
//! \br
//! Plug-in developers using the C++ ARA Library can use the ARA::PlugIn::RegionSequence class.
//! @{
//! Reference to the plug-in side representation of a region sequence (opaque to the host).
ARA_ADDENDUM(2_0_Draft) typedef ARA_REF(ARARegionSequenceRef);
//! Reference to the host side representation of a region sequence (opaque to the plug-in).
ARA_ADDENDUM(2_0_Draft) typedef ARA_HOST_REF(ARARegionSequenceHostRef);
//! Region sequence properties.
//! Note that like all properties, a pointer to this struct is only valid for the duration of the
//! call receiving the pointer - the data must be evaluated/copied inside the call, and the pointer
//! must not be stored anywhere.
ARA_ADDENDUM(2_0_Draft) typedef struct ARARegionSequenceProperties
{
//! @see_Versioned_Structs
ARASize structSize;
//! User-readable name of the region sequence as displayed in the host.
//! The plug-in must copy the name, the pointer may be only valid for the duration of the call.
//! It may be NULL if the host cannot provide a name for the region sequence.
//! In that case, the host should not make up some dummy name just to satisfy the API, but
//! rather let the plug-in do this if desired - this way it can distinguish between a proper
//! name visible somewhere in the host and a dummy name implicitly derived from other state.
ARAUtf8String name;
//! Sort order of the region sequence in the host.
//! The index must allow for the plug-in to order the region sequences as shown in the host,
//! but the actual index values are not shown to the user. They can be arbitrary, but must
//! increase strictly monotonically.
ARAInt32 orderIndex;
//! Musical context in which the playback regions of the sequence will be edited and rendered.
//! Note that when rendering the playback regions via any plug-in instance, the time information
//! provided for this plug-in through the companion API must match this musical context.
ARAMusicalContextRef musicalContextRef;
//! Color associated with the region sequence in the host.
//! The plug-in must copy the color, the pointer may be only valid for the duration of the call.
//! It may be NULL if the host cannot provide a color for the region sequence.
ARA_ADDENDUM(2_0_Draft) const ARAColor * color;
} ARARegionSequenceProperties;
// Convenience constant for easy struct validation.
enum ARA_ADDENDUM(2_0_Draft) { kARARegionSequencePropertiesMinSize = ARA_IMPLEMENTED_STRUCT_SIZE(ARARegionSequenceProperties, musicalContextRef) };
//! @}
/***************************************************************************************************/
//! @defgroup Model_Audio_Source Audio Source
//! An audio source represents a continuous sequence of sampled audio data. Typically a host will
//! create an audio source object for each audio file used with ARA plug-ins.
//! Conceptually, the contents of an audio source are immutable (even though updates are possible,
//! this is an expensive process, and user edits based on the modified content may get lost).
//! An audio source is always owned by one document, and in turn owns any amount of associated
//! audio modifications.
//! Audio sources are persistent when storing documents.
//! \br
//! Plug-in developers using the C++ ARA Library can use the ARA::PlugIn::AudioSource class.
//! @{
//! Reference to the plug-in side representation of an audio source (opaque to the host).
typedef ARA_REF(ARAAudioSourceRef);
//! Reference to the host side representation of an audio source (opaque to the plug-in).
typedef ARA_HOST_REF(ARAAudioSourceHostRef);
//! Audio source properties.
//! Note that like all properties, a pointer to this struct is only valid for the duration of the
//! call receiving the pointer - the data must be evaluated/copied inside the call, and the pointer
//! must not be stored anywhere.
typedef struct ARAAudioSourceProperties
{
//! @see_Versioned_Structs
ARASize structSize;
//! User-readable name of the audio source as displayed in the host.
//! The plug-in must copy the name, the pointer may be only valid for the duration of the call.
//! It may be NULL if the host cannot provide a name for the audio source.
//! In that case, the host should not make up some dummy name just to satisfy the API, but
//! rather let the plug-in do this if desired - this way it can distinguish between a proper
//! name visible somewhere in the host and a dummy name implicitly derived from other state.
ARAUtf8String name;
//! ID used to re-connect model graph when archiving/unarchiving.
//! This ID must be unique for all audio sources within the document.
//! The plug-in must copy the persistentID, the pointer may be only valid for the duration of the call.
ARAPersistentID persistentID;
//! Total number of samples per channel of the contained audio material.
//! May only be changed while access to the audio source is disabled,
//! see ARADocumentControllerInterface::enableAudioSourceSamplesAccess().
ARASampleCount sampleCount;
//! Sample rate of the contained audio material.
//! May only be changed while access to the audio source is disabled,
//! see ARADocumentControllerInterface::enableAudioSourceSamplesAccess().
//! Note that the sample rate of the audio source may not match the sample rate(s) used in the
//! companion plug-in instances that render playback regions based on this audio source -
//! plug-ins must apply sample rate conversion as needed.
//! However, if the sample rate is changed, plug-ins are not required to translate their model
//! to the new sample rate, and may instead restart with a fresh analysis, causing all user
//! edits applied at the previous sample rate to be lost.
ARASampleRate sampleRate;
//! Count of discrete channels of the contained audio material.
//! May only be changed while access to the audio source is disabled,
//! see ARADocumentControllerInterface::enableAudioSourceSamplesAccess().
//! As with sample rate changes, plug-ins may discard all edits and start with a fresh analysis
//! if the channel count is changed.
ARAChannelCount channelCount;
//! Flag to indicating that the data is available in a resolution that cannot be represented
//! in 32 bit float samples without losing quality.
//! Depending on its internal algorithms, the plug-in may or may not base its decision to
//! read either 32 or 64 bit samples on this flag,
//! see ARAAudioAccessControllerInterface::createAudioReaderForSource().
ARABool merits64BitSamples;
} ARAAudioSourceProperties;
// Convenience constant for easy struct validation.
enum { kARAAudioSourcePropertiesMinSize = ARA_IMPLEMENTED_STRUCT_SIZE(ARAAudioSourceProperties, merits64BitSamples) };
//! @}
/***************************************************************************************************/
//! @defgroup Model_Audio_Modification Audio Modification
//! An audio modification contains a set of musical edits that the user has made to transform
//! the content of an audio source when rendered by the ARA plug-in.
//! An audio modification is always owned by one audio source, and in turn owns any amount of
//! associated playback regions.
//! Audio modifications are persistent when storing documents.
//! \br
//! Plug-in developers using the C++ ARA Library can use the ARA::PlugIn::AudioModification class.
//! @{
//! Reference to the plug-in side representation of an audio modification (opaque to the host).
typedef ARA_REF(ARAAudioModificationRef);
//! Reference to the host side representation of an audio modification (opaque to the plug-in).
typedef ARA_HOST_REF(ARAAudioModificationHostRef);
//! Audio modification properties.
//! Note that like all properties, a pointer to this struct is only valid for the duration of the
//! call receiving the pointer - the data must be evaluated/copied inside the call, and the pointer
//! must not be stored anywhere.
typedef struct ARAAudioModificationProperties
{
//! @see_Versioned_Structs
ARASize structSize;
//! User-readable name of the audio modification as displayed in the host.
//! The plug-in must copy the name, the pointer may be only valid for the duration of the call.
//! It may be NULL if the host cannot provide a name for the audio modification.
//! In that case, the host should not make up some name (e.g. derived from the audio source), but
//! rather let the plug-in do this if desired - this way it can distinguish between a proper name
//! visible somewhere in the host and a dummy name implicitly derived from other state.
ARAUtf8String name;
//! ID used to re-connect model graph when archiving/unarchiving.
//! This ID must be unique for all audio modifications within the document.
//! The plug-in must copy the persistentID, the pointer may be only valid for the duration of the call.
ARAPersistentID persistentID;
} ARAAudioModificationProperties;
// Convenience constant for easy struct validation.
enum { kARAAudioModificationPropertiesMinSize = ARA_IMPLEMENTED_STRUCT_SIZE(ARAAudioModificationProperties, persistentID) };
//! @}
/***************************************************************************************************/
//! @defgroup Model_Playback_Region Playback Region
//! A playback region is a reference to an arbitrary time section of an audio modification,
//! mapped to a certain section of playback time.
//! It is linked to a region sequence, which in turn is linked to a musical context.
//! All playback regions that share the same audio modification play back the same musical
//! content, but may adapt that content to the given section of the musical context and to the
//! content of other regions in the same region sequence (see content based fades).
//! Note that if a plug-in offers any user settings to control this adaptation (such as groove settings),
//! then these settings should be part of the audio modification state, not of the individual
//! playback regions.
//! A playback is always owned by one audio modification, and refers to a region sequence.
//! Playback regions are not persistent when storing documents, instead the host re-creates them
//! as needed.
//! \br
//! Plug-in developers using the C++ ARA Library can use the ARA::PlugIn::PlaybackRegion class.
//! @{
//! Reference to the plug-in side representation of a playback region (opaque to the host).
typedef ARA_REF(ARAPlaybackRegionRef);
//! Reference to the host side representation of a playback region (opaque to the plug-in).
typedef ARA_HOST_REF(ARAPlaybackRegionHostRef);
//! Playback region transformations.
//! Plug-ins may or may not support all transformations that can be configured in a playback region.
//! They express these capabilities at factory level, and the host must respect this.
//! Also used in ARAFactory::supportedPlaybackTransformationFlags.
typedef ARA_32_BIT_ENUM(ARAPlaybackTransformationFlags)
{
//! Named constant if no flags are set.
//! If no flags are set, the modification is played back "as is", without further adoption
//! to the given playback situation.
kARAPlaybackTransformationNoChanges = 0,
//! Time-stretching enable flag.
//! If time-stretching is supported by the plug-in, the host can use this flag to enable it.
//! If disabled, the host must always specify the same duration in modification and playback time,
//! and the plug-in should ignore ARAPlaybackRegionProperties::durationInModificationTime.
kARAPlaybackTransformationTimestretch = 1 << 0,
//! Time-stretching tempo configuration flag.
//! If kARAPlaybackTransformationTimestretch is set, this flag allows to distinguish whether
//! the stretching shall be done in a strictly linear fashion (flag is off) or whether it
//! shall reflect the tempo relationship between the musical context and the content of the
//! audio modification (flag is on).
kARAPlaybackTransformationTimestretchReflectingTempo = 1 << 1,
ARA_ADDENDUM(2_0_Draft) kARAPlaybackTransformationContentBasedFadeAtTail = 1 << 2, //!< see ::kARAPlaybackTransformationContentBasedFades
ARA_ADDENDUM(2_0_Draft) kARAPlaybackTransformationContentBasedFadeAtHead = 1 << 3, //!< see ::kARAPlaybackTransformationContentBasedFades
//! Content-based fades enabling flags.
//! These flags are used to enable smart, content-based fades at either end of the playback region.
//! If supported by the plug-in, the host no longer needs to apply its regular overall fades at
//! region borders, but can instead delegate this functionality to the plug-in.
//! Based on the region sequence grouping, the plug-in can determine neighboring regions and
//! utilize head and tail time to calculate a smart, musical transition.
//! Even when no neighboring region is found, it may be appropriate to fade in or out to avoid
//! cutting off signals abruptly.
//! Note that while the transformation of a playback region can be defined separately for each
//! border of the region, it must be enabled for either both or neither border in the
//! ARAFactory::supportedPlaybackTransformationFlags.
ARA_ADDENDUM(2_0_Draft) kARAPlaybackTransformationContentBasedFades = kARAPlaybackTransformationContentBasedFadeAtHead | kARAPlaybackTransformationContentBasedFadeAtTail,
};
//! Playback region properties.
//! Note that like all properties, a pointer to this struct is only valid for the duration of the
//! call receiving the pointer - the data must be evaluated/copied inside the call, and the pointer
//! must not be stored anywhere.
typedef struct ARAPlaybackRegionProperties
{
//! @see_Versioned_Structs
ARASize structSize;
//! Configuration of possible transformations upon playback, i.e. time-stretching etc.
//! The host may only enable flags that are listed in ARAFactory::supportedPlaybackTransformationFlags.
ARAPlaybackTransformationFlags transformationFlags;
//! #startInModificationTime and #durationInModificationTime define the
//! audible audio modification time range. This section of the modification's audio data will
//! be mapped to the song playback time range defined below as configured by the #transformationFlags,
//! including optional time stretching. See @ref sec_ManipulatingTheTiming for more information.
ARATimePosition startInModificationTime;
//! See #startInModificationTime. \br
//! Plug-ins must deal with #durationInModificationTime being 0.0.
ARATimeDuration durationInModificationTime;
//! #startInPlaybackTime and #durationInPlaybackTime define the relationship between the
//! audible modification time range and the song playback time in seconds as communicated
//! via the companion API.
//! Musical context content (such as ::kARAContentTypeTempoEntries) is also expressed
//! in song playback time.
ARATimePosition startInPlaybackTime;
//! See #startInPlaybackTime. \br
//! Plug-ins must deal with #durationInPlaybackTime being 0.0.
ARATimeDuration durationInPlaybackTime;
//! Musical context in which the playback region will be edited and rendered.
//! Note that when rendering the playback region via any plug-in instance, the time information
//! provided for this plug-in through the companion API must match this musical context.
//! \deprecated
//! No longer used since adding region sequences in ARA 2.0, which already define the musical
//! context for all their respective regions. If structSize indicates that a sequence is used
//! (i.e. when using ARA 2.0 or higher), this field must be ignored by plug-ins. Hosts are
//! free to additionally set a valid musical context if desired for ARA 1 backwards compatibility,
//! or leave the field uninitialized otherwise.
ARA_DEPRECATED(2_0_Draft) ARAMusicalContextRef musicalContextRef;
//! Region sequence with which the playback region is associated in the host.
ARA_ADDENDUM(2_0_Draft) ARARegionSequenceRef regionSequenceRef;
//! User-readable name of the playback region as displayed in the host.
//! The plug-in must copy the name, the pointer may be only valid for the duration of the call.
//! It may be NULL if the host cannot provide a name for the audio modification.
//! In that case, the host should not make up some name (e.g. derived from the audio source), but
//! rather let the plug-in do this if desired - this way it can distinguish between a proper name