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.
220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/musa-dsl/datasets/p.rb', line 220 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.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/musa-dsl/datasets/p.rb', line 134 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.
189 190 191 192 193 194 195 196 197 |
# File 'lib/musa-dsl/datasets/p.rb', line 189 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 |