Module: Musa::Datasets::P
- Includes:
- Dataset
- Defined in:
- lib/musa-dsl/datasets/p.rb
Overview
Point series: sequential points in time with durations.
P (Point series) represents sequential points in time as arrays with alternating structure: [point, duration, point, duration, point, ...].
Structure
The array alternates between points and durations:
[point₀, duration₀, point₁, duration₁, point₂]
- Points (odd positions): Any data (numbers, hashes, complex structures, etc.)
- Durations (even positions): Time between points (numbers)
- Last point: Final point has no duration (sequence end)
This compact format efficiently represents timed sequences without repeating time information.
Conversions
P can be converted to two different representations:
1. Timed Series (to_timed_serie)
Converts to series of AbsTimed events with absolute time and value. Each value gets a timestamp based on cumulative durations.
p = [60, 4, 64, 8, 67].extend(P)
serie = p.to_timed_serie
# Yields:
# { time: 0, value: 60 }
# { time: 1.0, value: 64 } (4 * base_duration = 1.0)
# { time: 3.0, value: 67 } (8 * base_duration = 2.0)
2. Parameter Segment Series (to_ps_serie)
Converts to series of PS (Parameter Segment) objects representing continuous changes between consecutive points.
p = [60, 4, 64, 8, 67].extend(P)
serie = p.to_ps_serie
# Yields PS objects:
# { from: 60, to: 64, duration: 1.0, right_open: true }
# { from: 64, to: 67, duration: 2.0, right_open: false }
Point Transformation
The #map method transforms points while preserving durations:
p = [60, 4, 64, 8, 67].extend(P)
p2 = p.map { |point| point + 12 }
# => [72, 4, 76, 8, 79]
# Durations unchanged, points transformed
Defined Under Namespace
Classes: PtoTimedSerie
Instance Method Summary collapse
-
#map {|point| ... } ⇒ P
Maps over points, preserving durations.
-
#to_ps_serie(base_duration: nil) ⇒ Musa::Series::Serie<PS>
Converts to series of parameter segments.
-
#to_timed_serie(time_start: nil, time_start_component: nil, base_duration: nil) ⇒ PtoTimedSerie
Converts to series of timed events (AbsTimed).
Instance Method Details
#map {|point| ... } ⇒ P
Maps over points, preserving durations.
Transforms each point (odd positions) using the block while keeping durations (even positions) unchanged.
189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/musa-dsl/datasets/p.rb', line 189 def map(&block) i = 0 clone.map! do |element| # Process with block only the points (points are the alternating elements because P # structure is <point> <duration> <point> <duration> <point>) # if (i += 1) % 2 == 1 block.call(element) else element end end end |
#to_ps_serie(base_duration: nil) ⇒ Musa::Series::Serie<PS>
Converts to series of parameter segments.
Creates Musa::Datasets::PS objects representing continuous changes from each point to the next. Useful for glissandi, parameter sweeps, or any continuous interpolation between points.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/musa-dsl/datasets/p.rb', line 115 def to_ps_serie(base_duration: nil) # A quarter of a bar. Not "a quarter note": that is what it lasts in 4/4 # and nowhere else -- durations are fractions of a bar throughout the # library (see {Musa::Datasets::AbsD}), and the two readings part company # as soon as the meter is not 4/4. base_duration ||= 1/4r # TODO if instead of using clone (needed because of p.shift) we use index counter the P elements would be evaluated on the last moment Musa::Series::Constructors.E(clone, base_duration) do |p, base_duration| (p.size >= 3) ? { from: p.shift, duration: p.shift * base_duration, to: p.first, right_open: (p.length > 1) }.extend(PS).tap { |_| _.base_duration = base_duration } : nil end end |
#to_timed_serie(time_start: nil, time_start_component: nil, base_duration: nil) ⇒ PtoTimedSerie
Converts to series of timed events (AbsTimed).
Creates series yielding AbsTimed events with absolute time and value. Each value is emitted at its calculated time point based on cumulative durations.
160 161 162 163 164 165 166 167 168 |
# File 'lib/musa-dsl/datasets/p.rb', line 160 def to_timed_serie(time_start: nil, time_start_component: nil, base_duration: nil) time_start ||= 0r time_start += self.first[time_start_component] if time_start_component # A quarter of a bar; see the note in #to_ps_serie above. base_duration ||= 1/4r PtoTimedSerie.new(self, base_duration, time_start) end |