UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
rada_decode.h
Go to the documentation of this file.
1// Copyright Epic Games Tools, LLC. All Rights Reserved.
2#pragma once
3#include <stdint.h> // uint*_t
4#include <stddef.h> // size_t
5
6#include "rada_file_header.h"
7
8struct RadAContainer;
9
10/*
11 Rad Audio Container
12
13 This is a file format containing Rad Audio encoded data. It provides
14 multi channel streams with a seek table, as well as some metadata to
15 make decoding a bit more predictable memory-wise.
16
17 The data on disk is ordered as:
18 FileHeader
19 SeekHeader, if seek table is present
20 Rad Audio Stream Headers
21 SeekTable, if seek table is present.
22 Encoded blocks.
23*/
24
25// RADA compatibility version - if these are the same the exports are named the same so we expect
26// that if the linker selects a different copy they all work.
27#define RADA_LIBRARY_VERSION 1
28
29#ifndef RR_STRING_JOIN3
30#define RR_STRING_JOIN3(arg1, arg2, arg3) RR_STRING_JOIN_DELAY3(arg1, arg2, arg3)
31#define RR_STRING_JOIN_DELAY3(arg1, arg2, arg3) RR_STRING_JOIN_IMMEDIATE3(arg1, arg2, arg3)
32#define RR_STRING_JOIN_IMMEDIATE3(arg1, arg2, arg3) arg1 ## arg2 ## arg3
33#endif
34
35#ifndef RR_STRING_JOIN
36#define RR_STRING_JOIN(arg1, arg2) RR_STRING_JOIN_DELAY(arg1, arg2)
37#define RR_STRING_JOIN_DELAY(arg1, arg2) RR_STRING_JOIN_IMMEDIATE(arg1, arg2)
38#define RR_STRING_JOIN_IMMEDIATE(arg1, arg2) arg1 ## arg2
39#endif
40
41#ifdef RADA_WRAP
42#define RADA_NAME(name) RR_STRING_JOIN3(RADA_WRAP, name##_, RADA_LIBRARY_VERSION )
43#else
44#error RADA_WRAP must be defined (MIRA or UERA)
45#endif
46
47#define RadAGetFileHeader RADA_NAME(RadAGetFileHeader)
48#define RadAGetSeekTableHeader RADA_NAME(RadAGetSeekTableHeader)
49#define RadAStripSeekTable RADA_NAME(RadAStripSeekTable)
50#define RadAGetMemoryNeededToOpen RADA_NAME(RadAGetMemoryNeededToOpen)
51#define RadAOpenDecoder RADA_NAME(RadAOpenDecoder)
52#define RadADecodeSeekTable RADA_NAME(RadADecodeSeekTable)
53#define RadADirectSeekTableLookup RADA_NAME(RadADirectSeekTableLookup)
54#define RadASeekTableLookup RADA_NAME(RadASeekTableLookup)
55#define RadAExamineBlock RADA_NAME(RadAExamineBlock)
56#define RadANotifySeek RADA_NAME(RadANotifySeek)
57#define RadADecodeBlock RADA_NAME(RadADecodeBlock)
58#define RadAInterleave RADA_NAME(RadAInterleave)
59
60// The number of bytes the seek table takes up on disk. It exists after
61// RadABytesToOpen, and before RadABytesToFirstBlock
62static uint32_t RadAGetSeekTableSizeOnDisk(const RadAFileHeader* FileHeader)
63{
64 if (FileHeader == 0 || FileHeader->seek_table_entry_count == 0)
65 return 0;
66 // align the bit count to 64 then convert to bytes;
67 uint32_t seek_table_bits = FileHeader->bits_for_seek_table_samples + FileHeader->bits_for_seek_table_bytes;
68 uint32_t seek_table_bytes = 8 * ((seek_table_bits * FileHeader->seek_table_entry_count + 63) / 64);
69 return seek_table_bytes;
70}
71
72// Returns the number of bytes of the rada file have to be in memory in order to call
73// RadAOpenDecoder. Since this requires a valid file header, getting the size to open
74// is a two phase operation: read the file header (sizeof(FileHeader)), then query the file header
75// with this function.
76//
77// This is also the offset to the first encoded block.
78static uint32_t RadAGetBytesToOpen(const RadAFileHeader* FileHeader)
79{
80 if (FileHeader == 0)
81 return 0;
82 uint32_t SizeWithoutSeekTable = sizeof(RadAFileHeader) + FileHeader->rada_header_bytes;
83 if (FileHeader->seek_table_entry_count)
84 {
85 return SizeWithoutSeekTable + sizeof(RadASeekTableHeader) + RadAGetSeekTableSizeOnDisk(FileHeader);
86 }
88}
89
90static uint32_t RadAGetOffsetToSeekTable(const RadAFileHeader* FileHeader)
91{
92 if (FileHeader == 0 ||
93 FileHeader->seek_table_entry_count == 0)
94 return 0;
95 return sizeof(RadAFileHeader) + sizeof(RadASeekTableHeader) + FileHeader->rada_header_bytes;
96}
97
98// Returns a pointer to the file header from the given data. The header will be validated.
99// This function needs at least sizeof(RadAFileHeader) passed to it to succeed. If insufficient
100// data is provided, or the header is incorrect in any way, 0 is returned.
103
104// Retrieves the file header from an opened decoder.
105static const RadAFileHeader* RadAGetFileHeaderFromContainer(const RadAContainer* InContainer) { return (const RadAFileHeader*)InContainer; }
106
107// Removes the seek table, if present, from the given file and returns the new size of the data.
108// Returns 0 on invalid file.
110
111// Gets the size of the RadAContainer to pass to RadAOpenDecoder. You use this to determine how much to allocate
112// for the entirely of the decoder structure (note: you are responsible for allocating seek table space yourself)
113// returns:
114// 0 on success
115// -1 on bad data
116// >0 is the amount of file data we need to make progress in getting the result. This can happen multiple times
117// in a row.
119
120// InData is the file data loaded in to memory. The amount to read is specified by RadABytesToOpen(). InContainer
121// must be allocated to the size specified by RadAGetMemoryNeeded. When done decoding, no function needs to be called,
122// just free the container.
123// RadAContainer* Container = malloc(RadAGetMemoryNeeded());
124// RadAOpenDecoder(FileData, FileDataSize, Container, RadAGetMemoryNeeded());
125// Returns 1 on success, 0 on fail.
127
128
134
136{
137 // All seek table entries have been decoded
138 Done,
140 // The input data is invalid in some way
142 // The buffer provided needs to be advanced by the bytes consumed, filled up,
143 // and the function called again.
145
146 // The seek table output is too big for 32 bits, start over with 64 bits.
148};
149
150/*
151* Iteratively decode the seek table in to your own management structures. This is to facilitate allocating during opening or needing a large stack.
152*
153* InData is the on disk encoded seek table. This is offset from the beginning of the file at RadABytesToOpen(). This can be streamed
154* in chunks, but to get the entire table you'll need to overall provide RadASeekTableSizeOnDisk() to the function (at which point
155* it will return ::Done.
156*
157* OutSeekTableSamples and OutSeekTableBytes need to be point to arrays of either uint32s or uint64s based on whether InSeekTableIs64Bits, of
158* size InFileHeader->seek_table_entry_count.
159*
160* OutConsumed will emit how much of the buffer got consumed this run. This might not be completely consumed before more data is needed.
161*
162* You can of course just pass the entire seek table in one go.
163*
164* Roughly:
165*
166*
167* SeekTableEnumerationState EnumState;
168* for (;;)
169* {
170* size_t bytes_consumed = 0;
171* RadASeekTableReturn result = RadADecodeSeekTable(file_header, seek_table_buffer, seek_table_buffer_valid_bytes, false, &EnumState, ptr_to_samples, ptr_to_bytes, &bytes_consumed);
172*
173* if (result == RadASeekTableReturn::Done)
174* break;
175* if (result != RadASeekTableReturn::NeedsMoreData)
176* return failure;
177*
178* seek_table_bytes_remaining -= bytes_consumed;
179* seek_table_buffer_valid -= bytes_consumed;
180* if (seek_table_bytes_remaining == 0)
181* return MilesDecoderOpenReturnFail; // they asked for more data but exceed what they said they'd need!
182* }
183*/
185
186// Look up where a given frame is in the file without doing a full decoder open. This is a binary search on the seek table
187// and should be fairly fast.
188// The return is 0 on failure, or the byte location of the encoded block that will provide the given frame. OutFrameAtLocation
189// returns the frame that first gets emitted when decoding starts at that location, and OutFrameBlockSize will return the size
190// required to decode the first block at that location.
191//
192// NOTE!! OutFrameBlockSize will allow you to decode at least 1 block, however due to the mDCT nature of the codec,
193// one block must be "wasted" to prime the decoder before it starts to emit. So do not expect to get the desired frame out
194// after one decode, and you may need more than that amount. That just gets you *a* block.
196
197// Same as above, except if you've opened the decoder.
199
201{
202 // The buffer provided can be passed to RadADecodeBlock and expect to succeed.
203 Valid,
204 // We need more data in order to determine. OutBufferLenBytesNeeded contained how much we need.
206 // The buffer can't be decoded.
207 Invalid,
208};
209
210// Examine encoded data to determine how much data is needed to decode the next block.
212
213// This function must be called before RadADecodeBlock if data from the file is not provided sequentially.
215
216// A single call to RadADecodeBlock can never put more than this number of frames in to the output reservoir.
218
219#define RadADecodeBlock_Error -2
220#define RadADecodeBlock_Done -1
221
222/*
223* Decode a single block of encoded rad audio data.
224*
225* The data provided shoulid have passed a RadAExamineBlock check beforehand.
226* The return value is the number of frames decoded, or one of RadADecodeBlock_Error or
227* RadADecodeBlock_Done, which indicates end of file.
228*
229* At most RadADecodeBlock_MaxOutputFrames will be emitted into the output buffer.
230*
231* It is normal for 0 frames to get emitted after a seek or the beginning of the file.
232*
233* InBuffer should be advanced by OutConsumedBytes, which should then point at the next
234* block to pass to RadAExamineBlock.
235*/
237 const uint8_t* InBuffer, size_t InBufferLenBytes,
239 size_t* OutConsumedBytes);
240
241// utility function to interleave N buffers of float data into one output buffer of S16 (scales and clamps from -1.0 to 1 into -32768 to 32767)
242#define RADA_HAS_INTERLEAVING
243void RadAInterleave( int16_t * output, float const ** inputs, uint32_t input_count, uint32_t samples );
244
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define RadADecodeSeekTable
Definition rada_decode.h:52
#define RadADirectSeekTableLookup
Definition rada_decode.h:53
#define RadAGetSeekTableHeader
Definition rada_decode.h:48
RadAExamineBlockResult
Definition rada_decode.h:201
#define RadAOpenDecoder
Definition rada_decode.h:51
#define RadAExamineBlock
Definition rada_decode.h:55
#define RadAGetFileHeader
Definition rada_decode.h:47
RadASeekTableReturn
Definition rada_decode.h:136
#define RadASeekTableLookup
Definition rada_decode.h:54
#define RadANotifySeek
Definition rada_decode.h:56
#define RadAInterleave
Definition rada_decode.h:58
#define RadAStripSeekTable
Definition rada_decode.h:49
#define RadAGetMemoryNeededToOpen
Definition rada_decode.h:50
constexpr uint32_t RadADecodeBlock_MaxOutputFrames
Definition rada_decode.h:217
#define RadADecodeBlock
Definition rada_decode.h:57
Definition rada_decode.cpp:8
Definition rada_file_header.h:19
Definition rada_file_header.h:50
Definition rada_decode.h:130
SeekTableEnumerationState()
Definition rada_decode.h:132
uint64_t state[2]
Definition rada_decode.h:131