View Source Vtc.Framestamp.Range (vtc v0.17.5)

Holds a framestamp range.

struct-fields

Struct Fields

  • in: Start TC. Must be less than or equal to out.
  • out: End TC. Must be greater than or equal to in.
  • inclusive: See below for more information. Default: false

inclusive-vs-exclusive-ranges

Inclusive vs. Exclusive Ranges

Inclusive ranges treat the out framestamp as the last visible frame of a piece of footage. This style of timecode range is most often associated with AVID.

Exclusive framestamp ranges treat the out framestamp as the boundary where the range ends. This style of timecode range is most often associated with Final Cut and Premiere.

In mathematical notation, inclusive ranges are [in, out], while exclusive ranges are [in, out).

Link to this section Summary

Types

Whether the end point should be treated as the Range's boundary (:exclusive), or its last element (:inclusive).

t()

Range struct type.

Parse

As new/3, but raises on error.

Returns a range with an :in value of stamp_in and a duration of duration.

As with_duration/3, but raises on error.

Manipulate

Adds scalar to both range.in and range.out.

Wraps range with smpte_wrap_tod/1, then splits on SMPTE midnight, returning two ranges

As smpte_split_tod/1, but raises on error.

Wrap range.in to the nearest valid TOD (time-of-day) timecode.

As smpte_wrap_tod/1, but raises on error.

Adjusts range to have an exclusive out framestamp.

Adjusts range to have an inclusive out framestamp.

Inspect

Returns the duration in Framestamp of range.

Compare

Returns true if range contains framestamp. framestamp may be any value that implements Frames.

Returns the the range where a and b overlap/intersect.

As intersection, but returns a Range from 00:00:00:00 - 00:00:00:00 when there is no overlap.

Returns true if there is overlap between a and b.

Returns the range between two, non-overlapping ranges.

As separation, but returns a Range from 00:00:00:00 - 00:00:00:00 when there is overlap.

Functions

Callback implementation for Ecto.Type.embed_as/1.

Callback implementation for Ecto.Type.equal?/2.

Link to this section Types

@type out_type() :: :inclusive | :exclusive

Whether the end point should be treated as the Range's boundary (:exclusive), or its last element (:inclusive).

@type t() :: %Vtc.Framestamp.Range{
  in: Vtc.Framestamp.t(),
  out: Vtc.Framestamp.t(),
  out_type: out_type()
}

Range struct type.

Link to this section Parse

Link to this function

new(stamp_in, stamp_out, opts \\ [])

View Source
@spec new(
  stamp_in :: Vtc.Framestamp.t(),
  stamp_out :: Vtc.Framestamp.t() | Vtc.Source.Frames.t(),
  opts :: [{:out_type, out_type()}]
) :: {:ok, t()} | {:error, Exception.t() | Vtc.Framestamp.ParseError.t()}

Creates a new Range.

out_tc may be a Framestamp value for any value that implements the Frames protocol.

Returns an error if the resulting range would not have a duration greater or equal to 0, or if stamp_in and stamp_out do not have the same rate.

examples

Examples

iex> stamp_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> stamp_out = Framestamp.with_frames!("02:00:00:00", Rates.f23_98())
iex>
iex> result = Range.new(stamp_in, stamp_out)
iex> inspect(result)
"{:ok, <01:00:00:00 - 02:00:00:00 :exclusive <23.98 NTSC>>}"

Using a timecode string as b:

iex> stamp_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex>
iex> result = Range.new(stamp_in, "02:00:00:00")
iex> inspect(result)
"{:ok, <01:00:00:00 - 02:00:00:00 :exclusive <23.98 NTSC>>}"

Making a range with an inclusive out:

iex> stamp_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex>
iex> result = Range.new(stamp_in, "02:00:00:00", out_type: :inclusive)
iex> inspect(result)
"{:ok, <01:00:00:00 - 02:00:00:00 :inclusive <23.98 NTSC>>}"
Link to this function

new!(stamp_in, stamp_out, opts \\ [])

View Source
@spec new!(Vtc.Framestamp.t(), Vtc.Framestamp.t(), opts :: [{:out_type, out_type()}]) ::
  t()

As new/3, but raises on error.

Link to this function

with_duration(stamp_in, duration, opts \\ [])

View Source
@spec with_duration(
  stamp_in :: Vtc.Framestamp.t(),
  duration :: Vtc.Framestamp.t() | Vtc.Source.Frames.t(),
  opts :: [{:out_type, out_type()}]
) :: {:ok, t()} | {:error, Exception.t() | Vtc.Framestamp.ParseError.t()}

Returns a range with an :in value of stamp_in and a duration of duration.

duration may be a Framestamp value for any value that implements the Frames protocol. Returns an error if duration is less than 0 seconds or if stamp_in and stamp_out do not have the same rate.

examples

Examples

iex> stamp_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> duration = Framestamp.with_frames!("00:30:00:00", Rates.f23_98())
iex>
iex> result = Range.with_duration(stamp_in, duration)
iex> inspect(result)
"{:ok, <01:00:00:00 - 01:30:00:00 :exclusive <23.98 NTSC>>}"

Using a timecode string as b:

iex> stamp_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex>
iex> result = Range.with_duration(stamp_in, "00:30:00:00")
iex> inspect(result)
"{:ok, <01:00:00:00 - 01:30:00:00 :exclusive <23.98 NTSC>>}"

Making a range with an inclusive out:

iex> stamp_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex>
iex> result = Range.with_duration(stamp_in, "00:30:00:00", out_type: :inclusive)
iex> inspect(result)
"{:ok, <01:00:00:00 - 01:29:59:23 :inclusive <23.98 NTSC>>}"
Link to this function

with_duration!(stamp_in, duration, opts \\ [])

View Source
@spec with_duration!(
  Vtc.Framestamp.t(),
  Vtc.Framestamp.t(),
  opts :: [{:out_type, out_type()}]
) :: t()

As with_duration/3, but raises on error.

Link to this section Manipulate

Link to this function

shift(range, scalar, opts \\ [])

View Source
@spec shift(
  t(),
  Vtc.Framestamp.t() | Vtc.Source.Frames.t(),
  opts :: [
    inherit_rate: Vtc.Framestamp.inherit_opt(),
    round: Vtc.Framestamp.round()
  ]
) :: t()

Adds scalar to both range.in and range.out.

auto-casts Frames values.

options

Options

  • inherit_rate: Which side to inherit the framerate from in mixed-rate calculations. If false, this function will raise if range.in.rate does not match scalar.rate. Default: false.

  • round: How to round the result with respect to whole-frames when mixing framerates. Default: :closest.

examples

Examples

iex> stamp_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> range = Framestamp.Range.new!(stamp_in, "02:00:00:00")
iex>
iex> scalar = Framestamp.with_frames!("00:00:01:00", Rates.f23_98())
iex>
iex> Framestamp.Range.shift(range, scalar) |> inspect()
"<01:00:01:00 - 02:00:01:00 :exclusive <23.98 NTSC>>"
@spec smpte_split_tod(t()) ::
  {:ok, pre_midnight :: t(), next_day :: t() | nil}
  | {:error, Vtc.Framerate.InvalidSMPTEValueError.t()}

Wraps range with smpte_wrap_tod/1, then splits on SMPTE midnight, returning two ranges:

  • pre_midnight: Uses range.in. range.out is clipped to 24:00:00:00, inclusive.

  • next_day: range.in is set to 00:00:00:00. range.out is wrapped to valid TOD (time-of-day) timecode value. If range does not cross SMPTE midnight will be nil instead.

Returns error if range.in.rate is not NTSC or whole-frame. Time-of-day timecode is not defined for non-SMPTE framerates.

examples

Examples

Splits range that crosses midnight line:

iex> stamp_in = Framestamp.with_frames!("23:59:59:00", Rates.f23_98())
iex> stamp_out = Framestamp.with_frames!("24:01:00:00", Rates.f23_98())
iex> range = Framestamp.Range.new!(stamp_in, stamp_out)
iex> {:ok, pre_midnight, next_day} = Framestamp.Range.smpte_split_tod(range)
iex> inspect(pre_midnight)
"<23:59:59:00 - 24:00:00:00 :exclusive <23.98 NTSC>>"
iex> inspect(next_day)
"<00:00:00:00 - 00:01:00:00 :exclusive <23.98 NTSC>>"

With inclusive out:

iex> stamp_in = Framestamp.with_frames!("23:59:59:00", Rates.f23_98())
iex> stamp_out = Framestamp.with_frames!("24:01:00:00", Rates.f23_98())
iex> range = Framestamp.Range.new!(stamp_in, stamp_out, out_type: :inclusive)
iex> {:ok, pre_midnight, next_day} = Framestamp.Range.smpte_split_tod(range)
iex> inspect(pre_midnight)
"<23:59:59:00 - 23:59:59:23 :inclusive <23.98 NTSC>>"
iex> inspect(next_day)
"<00:00:00:00 - 00:01:00:00 :inclusive <23.98 NTSC>>"

Leaves alone ranges that do not cross midnight:

iex> stamp_in = Framestamp.with_frames!("22:59:59:00", Rates.f23_98())
iex> stamp_out = Framestamp.with_frames!("23:01:00:00", Rates.f23_98())
iex> range = Framestamp.Range.new!(stamp_in, stamp_out)
iex> {:ok, pre_midnight, nil} = Framestamp.Range.smpte_split_tod(range)
iex> inspect(pre_midnight)
"<22:59:59:00 - 23:01:00:00 :exclusive <23.98 NTSC>>"

Wraps invalid TOD (time-of-day) timecode:

iex> stamp_in = Framestamp.with_frames!("24:00:00:00", Rates.f23_98())
iex> stamp_out = Framestamp.with_frames!("24:01:00:00", Rates.f23_98())
iex> range = Framestamp.Range.new!(stamp_in, stamp_out)
iex> {:ok, pre_midnight, nil} = Framestamp.Range.smpte_split_tod(range)
iex> inspect(pre_midnight)
"<00:00:00:00 - 00:01:00:00 :exclusive <23.98 NTSC>>"
@spec smpte_split_tod!(t()) :: {pre_midnight :: t(), next_day :: t() | nil}

As smpte_split_tod/1, but raises on error.

raises

Raises

  • InvalidSMPTEValueError if range.in.rate is not NTSC or whole-frame. Time-of-day timecode is not defined for non-SMPTE framerates.
@spec smpte_wrap_tod(t()) ::
  {:ok, t()} | {:error, Vtc.Framerate.InvalidSMPTEValueError.t()}

Wrap range.in to the nearest valid TOD (time-of-day) timecode.

Framestamps with a SMPTE timecode of less than 00:00:00:00 will have 24:00:00:00 recursively added until they are positive.

Framestamps with a SMPTE timecode of greater than or equal to 24:00:00:00 will have 24:00:00:00 subtracted until they are less than 24:00:00:00.

Returned out point is always greater than in point, and may exceed 24:00:00:00 if required for duration. If this behavior is not desirable, see smpte_split_tod/1.

Returns error if range.in.rate is not NTSC or whole-frame. Time-of-day timecode is not defined for non-SMPTE framerates.

examples

Examples

Adjusts ranges entirely outside of valid time-of-day timecode:

iex> stamp_in = Framestamp.with_frames!("24:00:00:00", Rates.f23_98())
iex> stamp_out = Framestamp.with_frames!("24:01:00:00", Rates.f23_98())
iex> range = Framestamp.Range.new!(stamp_in, stamp_out)
iex> {:ok, wrapped} = Framestamp.Range.smpte_wrap_tod(range)
iex> inspect(wrapped)
"<00:00:00:00 - 00:01:00:00 :exclusive <23.98 NTSC>>"

Does not adjust ranges with an in-point that is valid for time-of-day timecode:

iex> stamp_in = Framestamp.with_frames!("23:59:59:00", Rates.f23_98())
iex> stamp_out = Framestamp.with_frames!("24:01:00:00", Rates.f23_98())
iex> range = Framestamp.Range.new!(stamp_in, stamp_out)
iex> {:ok, wrapped} = Framestamp.Range.smpte_wrap_tod(range)
iex> inspect(wrapped)
"<23:59:59:00 - 24:01:00:00 :exclusive <23.98 NTSC>>"

Adjust negative ranges to wrap back from 24:00:00:00:

iex> stamp_in = Framestamp.with_frames!("-01:00:00:00", Rates.f23_98())
iex> stamp_out = Framestamp.with_frames!("-00:59:50:00", Rates.f23_98())
iex> range = Framestamp.Range.new!(stamp_in, stamp_out)
iex> {:ok, wrapped} = Framestamp.Range.smpte_wrap_tod(range)
iex> inspect(wrapped)
"<23:00:00:00 - 23:00:10:00 :exclusive <23.98 NTSC>>"
@spec smpte_wrap_tod!(t()) :: t()

As smpte_wrap_tod/1, but raises on error.

raises

Raises

  • InvalidSMPTEValueError if range.in.rate is not NTSC or whole-frame. Time-of-day timecode is not defined for non-SMPTE framerates.
Link to this function

with_exclusive_out(range)

View Source
@spec with_exclusive_out(t()) :: t()

Adjusts range to have an exclusive out framestamp.

examples

Examples

iex> stamp_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> range = Range.new!(stamp_in, "02:00:00:00", out_type: :inclusive)
iex>
iex> result = Range.with_exclusive_out(range)
iex> inspect(result)
"<01:00:00:00 - 02:00:00:01 :exclusive <23.98 NTSC>>"
Link to this function

with_inclusive_out(range)

View Source
@spec with_inclusive_out(t()) :: t()

Adjusts range to have an inclusive out framestamp.

examples

Examples

iex> stamp_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> range = Range.new!(stamp_in, "02:00:00:00")
iex>
iex> result = Range.with_inclusive_out(range)
iex> inspect(result)
"<01:00:00:00 - 01:59:59:23 :inclusive <23.98 NTSC>>"

Link to this section Inspect

@spec duration(t()) :: Vtc.Framestamp.t()

Returns the duration in Framestamp of range.

examples

Examples

iex> stamp_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> range = Range.new!(stamp_in, "01:30:00:00")
iex>
iex> result = Range.duration(range)
iex> inspect(result)
"<00:30:00:00 <23.98 NTSC>>"

Link to this section Compare

Link to this function

contains?(range, framestamp)

View Source
@spec contains?(t(), Vtc.Framestamp.t() | Vtc.Source.Frames.t()) :: boolean()

Returns true if range contains framestamp. framestamp may be any value that implements Frames.

examples

Examples

iex> stamp_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> range = Range.new!(stamp_in, "01:30:00:00")
iex>
iex> Range.contains?(range, "01:10:00:00")
true
iex> Range.contains?(range, "01:40:00:00")
false
Link to this function

intersection(a, b, opts \\ [])

View Source
@spec intersection(
  t(),
  t(),
  inherit_rate: Vtc.Framestamp.inherit_opt(),
  inherit_out_type: Vtc.Framestamp.inherit_opt()
) :: {:ok, t()} | {:error, :none}

Returns the the range where a and b overlap/intersect.

Returns {:error, :none} if the two ranges do not intersect.

options

Options

  • inherit_rate: Which side to inherit the framerate from in mixed-rate calculations. If false, this function will raise if a's rate does not match b's rate. Default: false.

  • inherit_out_type: Which side to inherit the out type from when a.out_type does not match b.out_type. If false, this function will raise if a's rate does not match b's rate. Default: false.

examples

Examples

iex> a_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> a = Range.new!(a_in, "02:00:00:00", out_type: :inclusive)
iex>
iex> b_in = Framestamp.with_frames!("01:50:00:00", Rates.f23_98())
iex> b = Range.new!(b_in, "02:30:00:00", out_type: :inclusive)
iex>
iex> result = Range.intersection(a, b)
iex> inspect(result)
"{:ok, <01:50:00:00 - 02:00:00:00 :inclusive <23.98 NTSC>>}"
iex> a_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> a = Range.new!(a_in, "02:00:00:00", out_type: :inclusive)
iex>
iex> b_in = Framestamp.with_frames!("02:10:00:00", Rates.f23_98())
iex> b = Range.new!(b_in, "03:30:00:00", out_type: :inclusive)
iex> Range.intersection(a, b)
{:error, :none}
Link to this function

intersection!(a, b, opts \\ [])

View Source
@spec intersection!(
  t(),
  t(),
  inherit_rate: Vtc.Framestamp.inherit_opt(),
  inherit_out_type: Vtc.Framestamp.inherit_opt()
) :: t()

As intersection, but returns a Range from 00:00:00:00 - 00:00:00:00 when there is no overlap.

options

Options

  • inherit_rate: Which side to inherit the framerate from in mixed-rate calculations. If false, this function will raise if a's rate does not match b's rate. Default: false.

  • inherit_out_type: Which side to inherit the out type from when a.out_type does not match b.out_type. If false, this function will raise if a's rate does not match b's rate. Default: false.

examples

Examples

iex> a_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> a = Range.new!(a_in, "02:00:00:00", out_type: :inclusive)
iex>
iex> b_in = Framestamp.with_frames!("02:10:00:00", Rates.f23_98())
iex> b = Range.new!(b_in, "03:30:00:00", out_type: :inclusive)
iex>
iex> result = Range.intersection!(a, b)
iex> inspect(result)
"<00:00:00:00 - -00:00:00:01 :inclusive <23.98 NTSC>>"
@spec overlaps?(t(), t()) :: boolean()

Returns true if there is overlap between a and b.

examples

Examples

iex> a_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> a = Range.new!(a_in, "02:00:00:00", out_type: :inclusive)
iex>
iex> b_in = Framestamp.with_frames!("01:50:00:00", Rates.f23_98())
iex> b = Range.new!(b_in, "02:30:00:00", out_type: :inclusive)
iex> Range.overlaps?(a, b)
true
iex> a_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> a = Range.new!(a_in, "02:00:00:00", out_type: :inclusive)
iex>
iex> b_in = Framestamp.with_frames!("02:10:00:00", Rates.f23_98())
iex> b = Range.new!(b_in, "03:30:00:00", out_type: :inclusive)
iex> Range.overlaps?(a, b)
false
Link to this function

separation(a, b, opts \\ [])

View Source
@spec separation(
  t(),
  t(),
  inherit_rate: Vtc.Framestamp.inherit_opt(),
  inherit_out_type: Vtc.Framestamp.inherit_opt()
) :: {:ok, t()} | {:error, :none}

Returns the range between two, non-overlapping ranges.

Returns {:error, :none} if the two ranges are not separated.

options

Options

  • inherit_rate: Which side to inherit the framerate from in mixed-rate calculations. If false, this function will raise if a's rate does not match b's rate. Default: false.

  • inherit_out_type: Which side to inherit the out type from when a.out_type does not match b.out_type. If false, this function will raise if a's rate does not match b's rate. Default: false.

examples

Examples

iex> a_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> a = Range.new!(a_in, "02:00:00:00", out_type: :inclusive)
iex>
iex> b_in = Framestamp.with_frames!("02:10:00:00", Rates.f23_98())
iex> b = Range.new!(b_in, "03:30:00:00", out_type: :inclusive)
iex>
iex> result = Range.separation(a, b)
iex> inspect(result)
"{:ok, <02:00:00:01 - 02:09:59:23 :inclusive <23.98 NTSC>>}"
iex> a_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> a = Range.new!(a_in, "02:00:00:00", out_type: :inclusive)
iex>
iex> b_in = Framestamp.with_frames!("01:50:00:00", Rates.f23_98())
iex> b = Range.new!(b_in, "02:30:00:00", out_type: :inclusive)
iex> Range.separation(a, b)
{:error, :none}
Link to this function

separation!(a, b, opts \\ [])

View Source
@spec separation!(
  t(),
  t(),
  inherit_rate: Vtc.Framestamp.inherit_opt(),
  inherit_out_type: Vtc.Framestamp.inherit_opt()
) :: t()

As separation, but returns a Range from 00:00:00:00 - 00:00:00:00 when there is overlap.

options

Options

  • inherit_rate: Which side to inherit the framerate from in mixed-rate calculations. If false, this function will raise if a's rate does not match b's rate. Default: false.

  • inherit_out_type: Which side to inherit the out type from when a.out_type does not match b.out_type. If false, this function will raise if a's rate does not match b's rate. Default: false.

examples

Examples

iex> a_in = Framestamp.with_frames!("01:00:00:00", Rates.f23_98())
iex> a = Range.new!(a_in, "02:00:00:00", out_type: :inclusive)
iex>
iex> b_in = Framestamp.with_frames!("01:50:00:00", Rates.f23_98())
iex> b = Range.new!(b_in, "02:30:00:00", out_type: :inclusive)
iex>
iex> result = Range.separation!(a, b)
iex> inspect(result)
"<00:00:00:00 - -00:00:00:01 :inclusive <23.98 NTSC>>"

Link to this section Functions

Callback implementation for Ecto.Type.embed_as/1.

Callback implementation for Ecto.Type.equal?/2.