Zongzi.Score.Note (zongzi v0.3.0)

Copy Markdown

Domain models and structures related to musical notes.

Summary

Types

metadata is scope => inner.

t()

Functions

Update note's duration.

Drags a note to a new key and/or start tick.

Fetches metadata.

Create new note.

Removes metadata.

Splits a note at an absolute tick position.

Modify the properties of an existing struct (modify id is not allowed).

Updates the note's annotation.

Update note's lyric.

Merges new metadata into the note's current metadata.

Validates a note.

Types

metadata()

@type metadata() :: %{required(binary()) => term()}

metadata is scope => inner.

It must be serializable.

list, doct, string, number, nil, etc.

t()

@type t() :: %Zongzi.Score.Note{
  annotation: String.t() | nil,
  duration_tick: Zongzi.Score.Tick.t(),
  id: Zongzi.Util.ID.t(),
  key: Zongzi.Score.Key.t(),
  lyric: String.t() | nil,
  metadata: metadata(),
  seq_id: Zongzi.Timeline.SeqID.t() | nil,
  start_tick: Zongzi.Score.Tick.t()
}

Functions

drag_duration(note, new_duraion)

@spec drag_duration(t(), non_neg_integer()) :: {:ok, t()} | {:error, term()}

Update note's duration.

drag_note(note, new_key_or_tick)

@spec drag_note(
  t(),
  %{
    optional(:start_tick) => Zongzi.Score.Tick.t(),
    optional(:key) => Zongzi.Score.Key.t()
  }
  | keyword(Zongzi.Score.Tick.t() | Zongzi.Score.Key.t())
) :: {:ok, t()} | {:error, term()}

Drags a note to a new key and/or start tick.

Only modifies the note itself; overlap constraints are enforced downstream.

Options

Accepts a map or keyword list. Only the following keys are recognised:

  • :start_tick — new start tick
  • :key — new pitch

get_metadata(note)

@spec get_metadata(t()) :: {:ok, metadata()}

Fetches metadata.

get_metadata(note, key)

@spec get_metadata(t(), key :: binary()) ::
  {:ok, term()} | {:error, {:key_not_found, key :: binary()}}

merge(note1, note2, merged_id, opts \\ [])

@spec merge(t(), t(), Zongzi.Util.ID.t(t()), keyword()) ::
  {:ok, t()} | {:error, term()}

Merges two notes.

merged_id is injected by the caller — Note does not generate IDs.

Options

  • :gap_tolerance — maximum allowed gap between notes in ticks (default 0: must be adjacent or overlapping)
  • :lyric_merger — pluggable lyric concatenation function (fn/2 -> ok | error); defaults to concatenating when both are non-nil

  • :annotation_merger — pluggable annotation merge function (fn/2 -> ok | error); defaults to the first non-nil value

Behaviour

  • Both notes must share the same pitch (compared via Key.to_midi/1)
  • Must overlap, or gap ≤ gap_tolerance
  • Returns {:ok, merged_note} with the given merged_id
  • Merged annotation takes the first non-nil value

new(attrs)

Create new note.

seq_id 默认由下游 Timeline.insert_note/2 分配, 反序列化时可以显式传入已有的 :seq_id

Examples

iex> new(%{id: "Note_12345"})
{:ok, %Note{id: "Note_12345"}}

iex> new(%{})
{:error, {:missing_id, "Note_"}}

remove_metadata(note, keys)

@spec remove_metadata(t(), :all | [binary()]) :: {:ok, t()}

Removes metadata.

Typically used at the end of a plugin lifecycle or before serialization.

split(note, split_tick, new_id, attrs \\ [])

@spec split(t(), Zongzi.Score.Tick.t(), Zongzi.Util.ID.t(t()), map() | keyword()) ::
  {:ok, t(), t()} | {:error, term()}

Splits a note at an absolute tick position.

Returns {:ok, note_before, note_after}. The trailing note gets a new ID. split_tick must fall strictly inside the note (start_tick < split_tick < end_tick).

attrs optionally overrides fields on the trailing note (e.g. a different lyric).

update(model, attrs)

Modify the properties of an existing struct (modify id is not allowed).

update_annotation(note, new_annotation)

@spec update_annotation(t(), String.t() | nil) :: {:ok, t()} | {:error, term()}

Updates the note's annotation.

Annotations are UI-only; the engine and plugins do not read them.

update_lyric(note, new_lyric)

@spec update_lyric(t(), String.t() | nil) :: {:ok, t()} | {:error, term()}

Update note's lyric.

update_metadata(note, new_metadata)

@spec update_metadata(t(), map()) :: {:ok, t()} | {:error, term()}

Merges new metadata into the note's current metadata.

validate(model)

Validates a note.

The following are invalid:

  • start_tick or duration_tick is negative
  • lyric is neither nil nor a string