Packages
vtc
0.7.0
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.9
0.16.8
0.16.7
0.16.6
0.16.5
0.16.4
0.16.2
0.16.1
0.16.0
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.15
0.13.14
0.13.13
0.13.12
0.13.11
0.13.10
0.13.9
0.13.8
0.13.7
0.13.6
0.13.5
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.1
0.11.0
0.10.10
0.10.9
0.10.8
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.2
0.9.1
0.9.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.3
0.7.2
0.7.1
0.7.0
0.6.1
0.6.0
0.5.3
0.5.2
0.5.1
0.4.0
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
A SMPTE timecode library for Elixir
Current section
Files
Jump to
Current section
Files
lib/sources/frames/feet_and_frames.ex
defmodule Vtc.Source.Frames.FeetAndFrames do
@moduledoc """
Holds Feet+Frames information.
## Fields
- `feet`: The amount of film in Feet that would run through the camera in a given
amount of time.
- `feet`: The number of frames left over after `feet` of film has run.
- `film_format`: The type of film this value represents.
"""
alias Vtc.FilmFormat
alias Vtc.Timecode
alias Vtc.Utils.Parse
@enforce_keys [:feet, :frames]
defstruct [:feet, :frames, film_format: :ff35mm_4perf]
@typedoc """
Contains only a single field for wrapping the underlying string.
"""
@type t() :: %__MODULE__{feet: integer(), frames: integer(), film_format: FilmFormat.t()}
@ff_regex ~r/(?P<negative>-)?(?P<feet>[0-9]+)\+(?P<frames>[0-9]+)/
@spec from_string(String.t(), FilmFormat.t()) :: {:ok, t()} | {:error, Timecode.ParseError.t()}
def from_string(ff_string, film_format \\ :ff35mm_4perf) do
with {:ok, groups} <- Parse.apply_regex(@ff_regex, ff_string) do
negative? = Map.fetch!(groups, "negative") == "-"
multiplier = if negative?, do: -1, else: 1
feet = groups |> Map.fetch!("feet") |> String.to_integer()
feet = feet * multiplier
frames = groups |> Map.fetch!("frames") |> String.to_integer()
frames = frames * multiplier
{:ok, %__MODULE__{feet: feet, frames: frames, film_format: film_format}}
end
end
@doc false
@spec from_timecode(
Timecode.t(),
opts :: [format: FilmFormat.t(), round: Timecode.round()]
) :: t()
def from_timecode(timecode, opts) do
film_format = Keyword.get(opts, :format, :ff35mm_4perf)
frames_opts = Keyword.take(opts, [:round])
total_frames = Timecode.frames(timecode, frames_opts)
frames_per_foot = FilmFormat.frames_per_foot(film_format)
feet = div(total_frames, frames_per_foot)
frames = rem(total_frames, frames_per_foot)
%__MODULE__{feet: feet, frames: frames, film_format: film_format}
end
end
defimpl String.Chars, for: Vtc.Source.Frames.FeetAndFrames do
alias Vtc.Source.Frames.FeetAndFrames
@spec to_string(FeetAndFrames.t()) :: binary()
def to_string(feet_frames) do
sign = if feet_frames.feet < 0, do: "-", else: ""
feet = feet_frames.feet |> abs() |> Integer.to_string()
frames = feet_frames.frames |> abs() |> Integer.to_string() |> String.pad_leading(2, "0")
"#{sign}#{feet}+#{frames}"
end
end
defimpl Inspect, for: Vtc.Source.Frames.FeetAndFrames do
alias Vtc.Source.Frames.FeetAndFrames
@spec inspect(FeetAndFrames.t(), Inspect.Opts.t()) :: String.t()
def inspect(feet_frames, _), do: "<#{feet_frames} #{inspect(feet_frames.film_format)}>"
end
defimpl Vtc.Source.Frames, for: Vtc.Source.Frames.FeetAndFrames do
@moduledoc """
Implements `Seconds` protocol for Premiere ticks.
"""
alias Vtc.FilmFormat
alias Vtc.Framerate
alias Vtc.Source.Frames
alias Vtc.Source.Frames.FeetAndFrames
@spec frames(FeetAndFrames.t(), Framerate.t()) :: Frames.result()
def frames(feet_frames, rate) do
frames_per_foor = FilmFormat.frames_per_foot(feet_frames.film_format)
frames = feet_frames.frames + feet_frames.feet * frames_per_foor
Frames.frames(frames, rate)
end
end