1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

AudioPlayHead: Use more descriptive FrameRate type

This commit is contained in:
reuk 2021-11-02 18:29:46 +00:00
parent 221a137526
commit 718307b516
No known key found for this signature in database
GPG key ID: 9ADCD339CFC98A11
4 changed files with 138 additions and 41 deletions

View file

@ -4,6 +4,26 @@ JUCE breaking changes
develop
=======
Change
------
AudioFrameRate::frameRate is now a class type instead of an enum.
Possible Issues
---------------
Code that read the old enum value will not compile.
Workaround
----------
Call frameRate.getType() to fetch the old enum type. Alternatively, use the new
getBaseRate(), isDrop(), isPullDown(), and getEffectiveRate() functions. The
new functions provide a more accurate description of the host's frame rate.
Rationale
---------
The old enum-based interface was not flexible enough to describe all the frame
rates that might be reported by a plugin host.
Change
------
FlexItem::alignSelf now defaults to "autoAlign" rather than "stretch".

View file

@ -60,6 +60,98 @@ public:
fpsUnknown = 99
};
/** More descriptive frame rate type. */
class JUCE_API FrameRate
{
public:
/** Creates a frame rate with a base rate of 0. */
FrameRate() = default;
/** Creates a FrameRate instance from a FrameRateType. */
FrameRate (FrameRateType type) : FrameRate (fromType (type)) {}
/** Gets the FrameRateType that matches the state of this FrameRate.
Returns fpsUnknown if this FrameRate cannot be represented by any of the
other enum fields.
*/
FrameRateType getType() const
{
switch (base)
{
case 24: return pulldown ? fps23976 : fps24;
case 25: return fps25;
case 30: return pulldown ? (drop ? fps2997drop : fps2997)
: (drop ? fps30drop : fps30);
case 60: return drop ? fps60drop : fps60;
}
return fpsUnknown;
}
/** Returns the plain rate, without taking pulldown into account. */
int getBaseRate() const { return base; }
/** Returns true if drop-frame timecode is in use. */
bool isDrop() const { return drop; }
/** Returns true if the effective framerate is actually equal to the base rate divided by 1.001 */
bool isPullDown() const { return pulldown; }
/** Returns the actual rate described by this object, taking pulldown into account. */
double getEffectiveRate() const { return pulldown ? (double) base / 1.001 : (double) base; }
/** Returns a copy of this object with the specified base rate. */
FrameRate withBaseRate (int x) const { return with (&FrameRate::base, x); }
/** Returns a copy of this object with drop frames enabled or disabled, as specified. */
FrameRate withDrop (bool x = true) const { return with (&FrameRate::drop, x); }
/** Returns a copy of this object with pulldown enabled or disabled, as specified. */
FrameRate withPullDown (bool x = true) const { return with (&FrameRate::pulldown, x); }
/** Returns true if this instance is equal to other. */
bool operator== (const FrameRate& other) const
{
const auto tie = [] (const FrameRate& x) { return std::tie (x.base, x.drop, x.pulldown); };
return tie (*this) == tie (other);
}
/** Returns true if this instance is not equal to other. */
bool operator!= (const FrameRate& other) const { return ! (*this == other); }
private:
static FrameRate fromType (FrameRateType type)
{
switch (type)
{
case fps23976: return FrameRate().withBaseRate (24).withPullDown();
case fps24: return FrameRate().withBaseRate (24);
case fps25: return FrameRate().withBaseRate (25);
case fps2997: return FrameRate().withBaseRate (30).withPullDown();
case fps30: return FrameRate().withBaseRate (30);
case fps2997drop: return FrameRate().withBaseRate (30).withDrop().withPullDown();
case fps30drop: return FrameRate().withBaseRate (30).withDrop();
case fps60: return FrameRate().withBaseRate (60);
case fps60drop: return FrameRate().withBaseRate (60).withDrop();
case fpsUnknown: break;
}
return {};
}
template <typename Member, typename Value>
FrameRate with (Member&& member, Value&& value) const
{
auto copy = *this;
copy.*member = std::forward<Value> (value);
return copy;
}
int base = 0;
bool drop = false, pulldown = false;
};
//==============================================================================
/** This structure is filled-in by the AudioPlayHead::getCurrentPosition() method.
*/
@ -95,7 +187,7 @@ public:
double ppqPositionOfLastBarStart = 0;
/** The video frame rate, if applicable. */
FrameRateType frameRate = FrameRateType::fps23976;
FrameRate frameRate = FrameRateType::fps23976;
/** True if the transport is currently playing. */
bool isPlaying = false;
@ -124,7 +216,7 @@ public:
//==============================================================================
bool operator== (const CurrentPositionInfo& other) const noexcept
{
auto tie = [] (const CurrentPositionInfo& i)
const auto tie = [] (const CurrentPositionInfo& i)
{
return std::tie (i.timeInSamples,
i.ppqPosition,

View file

@ -271,20 +271,9 @@ static void toProcessContext (Vst::ProcessContext& context, AudioPlayHead* playH
context.cycleStartMusic = position.ppqLoopStart;
context.cycleEndMusic = position.ppqLoopEnd;
switch (position.frameRate)
{
case AudioPlayHead::fps23976: fr.framesPerSecond = 24; fr.flags = FrameRate::kPullDownRate; break;
case AudioPlayHead::fps24: fr.framesPerSecond = 24; fr.flags = 0; break;
case AudioPlayHead::fps25: fr.framesPerSecond = 25; fr.flags = 0; break;
case AudioPlayHead::fps2997: fr.framesPerSecond = 30; fr.flags = FrameRate::kPullDownRate; break;
case AudioPlayHead::fps2997drop: fr.framesPerSecond = 30; fr.flags = FrameRate::kPullDownRate | FrameRate::kDropRate; break;
case AudioPlayHead::fps30: fr.framesPerSecond = 30; fr.flags = 0; break;
case AudioPlayHead::fps30drop: fr.framesPerSecond = 30; fr.flags = FrameRate::kDropRate; break;
case AudioPlayHead::fps60: fr.framesPerSecond = 60; fr.flags = 0; break;
case AudioPlayHead::fps60drop: fr.framesPerSecond = 60; fr.flags = FrameRate::kDropRate; break;
case AudioPlayHead::fpsUnknown: break;
default: jassertfalse; break; // New frame rate?
}
context.frameRate.framesPerSecond = (Steinberg::uint32) position.frameRate.getBaseRate();
context.frameRate.flags = (Steinberg::uint32) ((position.frameRate.isDrop() ? FrameRate::kDropRate : 0)
| (position.frameRate.isPullDown() ? FrameRate::kPullDownRate : 0));
if (position.isPlaying) context.state |= ProcessContext::kPlaying;
if (position.isRecording) context.state |= ProcessContext::kRecording;

View file

@ -2396,22 +2396,30 @@ private:
else
vstHostTime.flags &= ~Vst2::kVstTransportChanged;
switch (position.frameRate)
struct OptionalFrameRate
{
case AudioPlayHead::fps24: setHostTimeFrameRate (Vst2::kVstSmpte24fps, 24.0, position.timeInSeconds); break;
case AudioPlayHead::fps25: setHostTimeFrameRate (Vst2::kVstSmpte25fps, 25.0, position.timeInSeconds); break;
case AudioPlayHead::fps30: setHostTimeFrameRate (Vst2::kVstSmpte30fps, 30.0, position.timeInSeconds); break;
case AudioPlayHead::fps60: setHostTimeFrameRate (Vst2::kVstSmpte60fps, 60.0, position.timeInSeconds); break;
bool valid;
Vst2::VstInt32 rate;
};
case AudioPlayHead::fps23976: setHostTimeFrameRateDrop (Vst2::kVstSmpte239fps, 24.0, position.timeInSeconds); break;
case AudioPlayHead::fps2997: setHostTimeFrameRateDrop (Vst2::kVstSmpte2997fps, 30.0, position.timeInSeconds); break;
case AudioPlayHead::fps2997drop: setHostTimeFrameRateDrop (Vst2::kVstSmpte2997dfps, 30.0, position.timeInSeconds); break;
case AudioPlayHead::fps30drop: setHostTimeFrameRateDrop (Vst2::kVstSmpte30dfps, 30.0, position.timeInSeconds); break;
case AudioPlayHead::fps60drop: setHostTimeFrameRateDrop (Vst2::kVstSmpte599fps, 60.0, position.timeInSeconds); break;
case AudioPlayHead::fpsUnknown:
default: break;
const auto optionalFrameRate = [&fr = position.frameRate]() -> OptionalFrameRate
{
switch (fr.getBaseRate())
{
case 24: return { true, fr.isPullDown() ? Vst2::kVstSmpte239fps : Vst2::kVstSmpte24fps };
case 25: return { true, fr.isPullDown() ? Vst2::kVstSmpte249fps : Vst2::kVstSmpte25fps };
case 30: return { true, fr.isPullDown() ? (fr.isDrop() ? Vst2::kVstSmpte2997dfps : Vst2::kVstSmpte2997fps)
: (fr.isDrop() ? Vst2::kVstSmpte30dfps : Vst2::kVstSmpte30fps) };
case 60: return { true, fr.isPullDown() ? Vst2::kVstSmpte599fps : Vst2::kVstSmpte60fps };
}
return { false, Vst2::VstSmpteFrameRate{} };
}();
vstHostTime.flags |= optionalFrameRate.valid ? Vst2::kVstSmpteValid : 0;
vstHostTime.smpteFrameRate = optionalFrameRate.rate;
vstHostTime.smpteOffset = (int32) (position.timeInSeconds * 80.0 * position.frameRate.getEffectiveRate() + 0.5);
if (position.isLooping)
{
vstHostTime.cycleStartPos = position.ppqLoopStart;
@ -2506,18 +2514,6 @@ private:
}
//==============================================================================
void setHostTimeFrameRate (long frameRateIndex, double frameRate, double currentTime) noexcept
{
vstHostTime.flags |= Vst2::kVstSmpteValid;
vstHostTime.smpteFrameRate = (int32) frameRateIndex;
vstHostTime.smpteOffset = (int32) (currentTime * 80.0 * frameRate + 0.5);
}
void setHostTimeFrameRateDrop (long frameRateIndex, double frameRate, double currentTime) noexcept
{
setHostTimeFrameRate (frameRateIndex, frameRate * 1000.0 / 1001.0, currentTime);
}
bool restoreProgramSettings (const fxProgram* const prog)
{
if (compareMagic (prog->chunkMagic, "CcnK")