11namespace tracktion {
inline namespace engine
14#if TRACKTION_ENABLE_REX
16const char*
const RexAudioFormat::rexTempo =
"rex tempo";
17const char*
const RexAudioFormat::rexDenominator =
"rex denominator";
18const char*
const RexAudioFormat::rexNumerator =
"rex numerator";
19const char*
const RexAudioFormat::rexBeatPoints =
"rex beat points";
22inline const char* rexErrorToString (REX::REXError e)
noexcept
26 case REX::kREXError_NoError:
return "No error";
27 case REX::kREXError_OperationAbortedByUser:
return "Operation aborted by user";
28 case REX::kREXError_NoCreatorInfoAvailable:
return "No creator info available";
29 case REX::kREXError_OutOfMemory:
return "Out of Memory";
30 case REX::kREXError_FileCorrupt:
return "File is corrupt";
31 case REX::kREXError_REX2FileTooNew:
return "REX2 file is too new";
32 case REX::kREXError_FileHasZeroLoopLength:
return "File has a zero length for the loop";
33 case REX::kREXImplError_DLLNotInitialized:
return "DLL Not Initialized";
34 case REX::kREXImplError_DLLAlreadyInitialized:
return "DLL Already Initialized";
35 case REX::kREXImplError_InvalidHandle:
return "Invalid handle";
36 case REX::kREXImplError_InvalidSize:
return "Invalid size";
37 case REX::kREXImplError_InvalidArgument:
return "Invalid argument";
38 case REX::kREXImplError_InvalidSlice:
return "Invalid slice";
39 case REX::kREXImplError_InvalidSampleRate:
return "Invalid sample rate";
40 case REX::kREXImplError_BufferTooSmall:
return "Buffer too small";
41 case REX::kREXImplError_IsBeingPreviewed:
return "Is being previewed";
42 case REX::kREXImplError_NotBeingPreviewed:
return "Not being previewed";
43 case REX::kREXImplError_InvalidTempo:
return "Invalid tempo";
50static bool checkRexError (REX::REXError e)
52 if (e == REX::kREXError_NoError)
55 TRACKTION_LOG_ERROR (
"REX (Code " +
juce::String ((
int) e) +
"): " + rexErrorToString (e));
65 const REX::REXError e = REX::REXInitializeDLL();
67 if (e == REX::kREXImplError_DLLNotInitialized)
69 startupErrorMessage =
TRANS(
"Error loading Propellerheads REX DLL!");
71 else if (e != REX::kREXError_NoError)
73 startupErrorMessage =
TRANS(
"An unknown error occured with the Propellerheads REX format!");
76 initialised = checkRexError (e);
84 REX::REXUninitializeDLL();
88 bool initialised =
false;
94static RexSystem& getRexSystem()
100struct RexHandleWrapper
102 RexHandleWrapper (
const void* rexData,
size_t rexDataSize)
105 ok = checkRexError (REX::REXCreate (&handle, (
const char*) rexData,
106 (REX::REX_int32_t) rexDataSize,
nullptr,
nullptr));
113 REX::REXDelete (&handle);
116 REX::REXHandle handle;
127 :
juce::AudioFormatReader (sourceStream, name), buffer (2, 2)
133 loadedOk = decompress (rexData.getData(), rexData.getSize());
136 bool readSamples (
int*
const* destSamples,
int numDestChannels,
int startOffsetInDestBuffer,
137 juce::int64 startSampleInFile,
int numSamples)
override
140 clearSamplesBeyondAvailableLength (destSamples, numDestChannels, startOffsetInDestBuffer,
141 startSampleInFile, numSamples, lengthInSamples);
145 jassert (startOffsetInDestBuffer + numSamples <= buffer.getNumSamples());
147 for (
int i = 0; i < numDestChannels; ++i)
149 if (
float* dest = (
float*) destSamples[i])
151 dest += startOffsetInDestBuffer;
153 if (i < buffer.getNumChannels())
154 memcpy (dest, buffer.getReadPointer (i, (
int) startSampleInFile),
155 sizeof (
float) * (
size_t) numSamples);
168 bool decompress (
const void* rexData,
size_t rexDataSize)
171 auto& rex = getRexSystem();
175 if (! rex.initialised)
178 RexHandleWrapper handle (rexData, rexDataSize);
183 if (! checkRexError (REX::REXGetInfo (handle.handle, sizeof (info), &info)))
186 if (! checkRexError (REX::REXSetOutputSampleRate (handle.handle, info.fSampleRate)))
189 const double beats = info.fPPQLength / 15360.0;
190 const double bps = info.fTempo / (1000.0 * 60.0);
192 lengthInSamples = (SampleCount) ((beats / bps) * info.fSampleRate);
193 sampleRate = info.fSampleRate;
194 bitsPerSample = (
unsigned int) info.fBitDepth;
195 numChannels = (
unsigned int) info.fChannels;
196 usesFloatingPointData =
true;
198 buffer.
setSize ((
int) info.fChannels, (
int) lengthInSamples);
203 for (
int j = 0; j < info.fSliceCount; ++j)
205 REX::REXSliceInfo slcInfo;
206 if (! checkRexError (REX::REXGetSliceInfo (handle.handle, j,
sizeof(slcInfo), &slcInfo)))
211 if (! checkRexError (REX::REXRenderSlice (handle.handle, j, slcInfo.fSampleLength, (
float**)sliceData.getArrayOfWritePointers())))
214 auto offset = (SampleCount) ((slcInfo.fPPQPos / 15360.0) / (info.fTempo / (1000.0 * 60.0)) * info.fSampleRate);
215 auto numSamples = (
int)
std::min (lengthInSamples - offset, (SampleCount) slcInfo.fSampleLength);
218 for (
int i = 0; i < sliceData.getNumChannels(); ++i)
219 buffer.
addFrom (i, (
int) offset, sliceData, i, 0, numSamples);
224 metadataValues.set (RexAudioFormat::rexDenominator,
juce::String ((
int) info.fTimeSignDenom));
225 metadataValues.set (RexAudioFormat::rexNumerator,
juce::String ((
int) info.fTimeSignNom));
226 metadataValues.set (RexAudioFormat::rexTempo,
juce::String (info.fTempo / 1000.0));
228 if (beatPoints.
size() > 0)
229 metadataValues.set (RexAudioFormat::rexBeatPoints, beatPoints.
joinIntoString (
";"));
238RexAudioFormat::RexAudioFormat()
239 : AudioFormat (
NEEDS_TRANS(
"REX2 file"),
".rx2 .rex .rcy")
243RexAudioFormat::~RexAudioFormat()
255 if (! deleteStreamIfOpeningFails)
268 return getRexSystem().startupErrorMessage;
void setSize(int newNumChannels, int newNumSamples, bool keepExistingContent=false, bool clearExtraSpace=false, bool avoidReallocating=false)
int getNumChannels() const noexcept
void addFrom(int destChannel, int destStartSample, const AudioBuffer &source, int sourceChannel, int sourceStartSample, int numSamples, Type gainToApplyToSource=Type(1)) noexcept
String joinIntoString(StringRef separatorString, int startIndex=0, int numberOfElements=-1) const
int size() const noexcept
void add(String stringToAdd)
#define TRANS(stringLiteral)
#define NEEDS_TRANS(stringLiteral)
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.