Class: Musa::Markov::Markov
- Includes:
- Series::Serie::Base
- Defined in:
- lib/musa-dsl/generative/markov.rb
Overview
Markov chain serie generator.
Generates sequences of states following probabilistic transition rules. Implements Series::Serie interface for integration with series operations.
Instance Attribute Summary collapse
-
#finish ⇒ Object?
Finishing state (nil for infinite).
-
#random ⇒ Random
Random number generator.
-
#start ⇒ Object
Starting state.
-
#transitions ⇒ Hash
Transition rules (frozen).
Instance Method Summary collapse
-
#+(other) ⇒ Sequence
included
from Series::Operations
Appends another serie (operator alias for after).
-
#after(*series) ⇒ Sequence
included
from Series::Operations
Appends series sequentially.
-
#anticipate {|current, next_value| ... } ⇒ Anticipate
included
from Series::Operations
Evaluates block one step ahead (anticipate).
-
#autorestart ⇒ Autorestart
included
from Series::Operations
Auto-restarts serie when exhausted.
-
#buffered(sync: false) ⇒ BufferSerie, SyncBufferSerie
included
from Series::Operations
Creates a buffered serie allowing multiple independent iterations over same source.
-
#compact_timed ⇒ TimedCompacter
included
from Series::Operations
Removes timed events where all values are nil.
-
#composer { ... } ⇒ ComposerAsOperationSerie
included
from Series::Operations
Creates a composer transformation pipeline for complex multi-stage transformations.
-
#cut(length) ⇒ Cutter
included
from Series::Operations
Cuts serie into chunks of specified length.
-
#defined? ⇒ Boolean
included
from Series::Serie::Prototyping
Checks if serie state is defined (not undefined).
-
#flatten ⇒ Flattener
included
from Series::Operations
Flattens nested series into single level.
-
#flatten_timed ⇒ TimedFlattener
included
from Series::Operations
Splits compound timed values into individual timed events.
-
#hashify(*keys) ⇒ HashFromSeriesArray
included
from Series::Operations
Converts array values to hash with specified keys.
-
#infinite? ⇒ Boolean
Checks if Markov chain is infinite.
-
#initialize(transitions:, start:, finish: nil, random: nil) ⇒ void
constructor
Creates Markov chain generator.
-
#instance(built = nil) ⇒ Serie
(also: #i)
included
from Series::Serie::Prototyping
Creates or returns instance of serie.
-
#instance? ⇒ Boolean
included
from Series::Serie::Prototyping
Checks if serie is in instance state.
-
#lazy {|previous| ... } ⇒ LazySerieEval
included
from Series::Operations
Delays evaluation to next step (lazy evaluation).
-
#lock ⇒ Locker
included
from Series::Operations
Locks serie preventing further modifications.
-
#map(isolate_values: nil) {|value| ... } ⇒ ProcessWith
included
from Series::Operations
Maps values via transformation block.
-
#max_size(length) ⇒ LengthLimiter
included
from Series::Operations
Limits serie to maximum number of values.
-
#merge ⇒ MergeSerieOfSeries
included
from Series::Operations
Merges serie of series into single serie.
-
#multiplex(*indexed_series, **hash_series) ⇒ MultiplexSelector
included
from Series::Operations
Advances every serie and gives back the value of the one selected.
-
#process_with(**parameters) {|value, parameters| ... } ⇒ Processor
included
from Series::Operations
Transforms each value with a block whose parameters can change later.
-
#prototype ⇒ Serie
(also: #p)
included
from Series::Serie::Prototyping
Returns prototype of serie.
-
#prototype? ⇒ Boolean
included
from Series::Serie::Prototyping
Checks if serie is in prototype state.
-
#proxy ⇒ Object
included
from Series::Operations
TODO add test case.
-
#quantize(reference: nil, step: nil, value_attribute: nil, stops: nil, predictive: nil, left_open: nil, right_open: nil) ⇒ RawQuantizer, PredictiveQuantizer
included
from Series::Operations
Quantizes time-value serie to discrete steps.
-
#queued ⇒ QueueSerie
included
from Series::Operations
Wraps this serie in a queue.
-
#randomize(random: nil) ⇒ Randomizer
included
from Series::Operations
Randomizes order of values.
-
#remove(block = nil) {|value| ... } ⇒ Remover
included
from Series::Operations
Removes values matching condition.
-
#repeat(times = nil, condition: nil) { ... } ⇒ Repeater, InfiniteRepeater
included
from Series::Operations
Repeats serie multiple times or conditionally.
-
#reverse ⇒ Reverser
included
from Series::Operations
Reverses order of values.
-
#select(block = nil) {|value| ... } ⇒ Selector
included
from Series::Operations
Selects values matching condition.
-
#shift(shift) ⇒ Shifter
included
from Series::Operations
Rotates serie elements circularly.
-
#skip(length) ⇒ Skipper
included
from Series::Operations
Skips first N values.
-
#split ⇒ Splitter
included
from Series::Operations
Serie splitter for decomposing hash/array values into component series.
-
#state ⇒ Symbol
included
from Series::Serie::Prototyping
Returns current state of serie.
-
#switch(*indexed_series, **hash_series) ⇒ Switcher
included
from Series::Operations
Reads one value from whichever serie the selector names.
-
#switch_serie(*indexed_series, **hash_series) ⇒ SwitchFullSerie
included
from Series::Operations
Switches to entirely different series based on selector.
-
#undefined? ⇒ Boolean
included
from Series::Serie::Prototyping
Checks if serie is in undefined state.
-
#union_timed(*other_timed_series, key: nil, **other_key_timed_series) ⇒ TimedUnionOfArrayOfTimedSeries, TimedUnionOfHashOfTimedSeries
included
from Series::Operations
Combines this timed serie with others via TIMED_UNION.
-
#with(*with_series, on_restart: nil, isolate_values: nil, **with_key_series) {|main_value, with_values, with_key_values| ... } ⇒ With
(also: #eval)
included
from Series::Operations
Combines multiple series for mapping.
Constructor Details
#initialize(transitions:, start:, finish: nil, random: nil) ⇒ void
A generator passed in is used, not copied, so several series
sharing one draw from the same stream -- next_value advances it.
to_a does not, because it consumes a deep copy of the serie.
Creates Markov chain generator.
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/musa-dsl/generative/markov.rb', line 153 def initialize(transitions:, start:, finish: nil, random: nil) @transitions = transitions.clone.freeze @start = start @finish = finish # A seed is turned into a generator; a generator is kept as it is. The # second line used to overwrite the ivar the first had not set, so a # `Random` passed in was replaced by an unseeded one and the chain came # out different on every run while the caller believed it was pinned # (issue #79). @random = random.is_a?(Integer) ? Random.new(random) : random @random ||= Random.new @procedure_binders = {} mark_as_prototype! init end |
Instance Attribute Details
#finish ⇒ Object?
Returns finishing state (nil for infinite).
177 178 179 |
# File 'lib/musa-dsl/generative/markov.rb', line 177 def finish @finish end |
#random ⇒ Random
Returns random number generator.
180 181 182 |
# File 'lib/musa-dsl/generative/markov.rb', line 180 def random @random end |
#start ⇒ Object
Returns starting state.
174 175 176 |
# File 'lib/musa-dsl/generative/markov.rb', line 174 def start @start end |
#transitions ⇒ Hash
Returns transition rules (frozen).
183 184 185 |
# File 'lib/musa-dsl/generative/markov.rb', line 183 def transitions @transitions end |
Instance Method Details
#+(other) ⇒ Sequence Originally defined in module Series::Operations
Appends another serie (operator alias for after).
#after(*series) ⇒ Sequence Originally defined in module Series::Operations
Appends series sequentially.
Alias for MERGE - plays this serie, then others in sequence.
#anticipate {|current, next_value| ... } ⇒ Anticipate Originally defined in module Series::Operations
Evaluates block one step ahead (anticipate).
Block receives current value and NEXT value (peeked). Enables look-ahead transformations and transitions.
The block gets THREE values -- the previous one, the current one and the next -- and either end is nil where there is nothing.
#autorestart ⇒ Autorestart Originally defined in module Series::Operations
The serie ENDS at each pass -- yielding nil -- and restarts on the
next call. That nil is the signal that a pass finished, which is what
makes the repetition countable; it also means infinite? is false and
that to_a stops at the end of the first pass. For a serie with no
seam in it, use repeat.
Auto-restarts serie when exhausted.
Creates an infinite serie from an original serie that automatically restarts from beginning when it reaches the end.
#buffered(sync: false) ⇒ BufferSerie, SyncBufferSerie Originally defined in module Series::Operations
Creates a buffered serie allowing multiple independent iterations over same source.
Provides buffering mechanism enabling multiple "readers" to independently iterate over the same serie source without interfering with each other.
Buffering Modes
- Async (default): Buffers fill independently, each progresses at own pace
- Sync: All buffers synchronized, restart affects all
Use Cases
- Multiple voices reading same melodic sequence at different speeds
- Polyphonic playback from single source
- Canonic structures (rounds, fugues)
- Independent transformations of same base material
Memory Management
History is automatically cleaned when all buffers have progressed past old values, preventing unbounded memory growth.
#compact_timed ⇒ TimedCompacter Originally defined in module Series::Operations
Removes timed events where all values are nil.
Filters out temporal "gaps" where no sources have active values. Useful after union operations that create nil placeholders, or for cleaning sparse sequences.
Removal logic:
- Direct nil:
{ time: t, value: nil }→ removed - All-nil Hash:
{ time: t, value: { a: nil, b: nil } }→ removed - Partial Hash:
{ time: t, value: { a: 1, b: nil } }→ kept (has non-nil) - All-nil Array:
{ time: t, value: [nil, nil] }→ removed - Partial Array:
{ time: t, value: [1, nil] }→ kept (has non-nil)
#composer { ... } ⇒ ComposerAsOperationSerie Originally defined in module Series::Operations
Creates a composer transformation pipeline for complex multi-stage transformations.
Composer provides declarative DSL for building transformation pipelines with multiple inputs, outputs, and intermediate processing stages.
Composer Concepts
- Pipelines: Named transformation chains
- Inputs: Named input series (proxied and buffered)
- Outputs: Named output series
- Operations: Transformation steps in pipeline
- Auto-commit: Automatic finalization of pipelines
DSL Structure
A pipeline is declared by NAMING it and listing its operations; the names
are then wired together with route. Operations are symbols (reverse)
or hashes ({ map: ... }, { skip: 1 }, { S: [...] }). input and
output are pipelines like any other — they are simply the ones the
Composer creates for you, and can be renamed or multiplied through the
inputs: and outputs: keywords.
composer do
stage1 operation1, operation2
stage2 operation3
route input, to: stage1
route stage1, to: stage2
route stage2, to: output
end
Musical Applications
- Complex multi-voice processing
- Effect chains and routing
- Algorithmic composition pipelines
- Multi-stage transformations
- Modular synthesis-style routing
#cut(length) ⇒ Cutter Originally defined in module Series::Operations
Cuts serie into chunks of specified length.
Returns a serie of SERIES, each yielding length values.
The chunks are series and not arrays, which is what keeps the whole thing
lazy -- nothing is materialised until each chunk is consumed. Ask for the
arrays explicitly with to_a(recursive: true).
#defined? ⇒ Boolean Originally defined in module Series::Serie::Prototyping
Checks if serie state is defined (not undefined).
#flatten ⇒ Flattener Originally defined in module Series::Operations
Flattens nested series into single level.
Recursively consumes series elements that are themselves series.
#flatten_timed ⇒ TimedFlattener Originally defined in module Series::Operations
Splits compound timed values into individual timed events.
Converts events with Hash or Array values into separate timed events per element, preserving time and extra attributes. Direct values pass through unchanged.
Hash values → Hash of timed events (keyed by original keys):
{ time: 0, value: { a: 1, b: 2 }, velocity: { a: 80, b: 90 } }
# becomes:
{ a: { time: 0, value: 1, velocity: 80 },
b: { time: 0, value: 2, velocity: 90 } }
Array values → Array of timed events (indexed):
{ time: 0, value: [1, 2], velocity: [80, 90] }
# becomes:
[{ time: 0, value: 1, velocity: 80 },
{ time: 0, value: 2, velocity: 90 }]
Direct values → Pass through unchanged (already flat)
Use Cases
- Separate polyphonic events into individual voices
- Split multi-track sequences for independent processing
- Prepare for voice-specific routing via
split - Enable per-voice filtering with
compact_timed
#hashify(*keys) ⇒ HashFromSeriesArray Originally defined in module Series::Operations
Converts array values to hash with specified keys.
Takes array-valued serie and converts to hash using provided keys.
#infinite? ⇒ Boolean
Checks if Markov chain is infinite.
250 251 252 |
# File 'lib/musa-dsl/generative/markov.rb', line 250 def infinite? @finish.nil? end |
#instance(built = nil) ⇒ Serie Also known as: i Originally defined in module Series::Serie::Prototyping
Creates or returns instance of serie.
- If already instance, returns self
- If prototype, creates new instance by cloning
- If undefined, raises PrototypingError
Cloning Process
- Clones serie structure
- Marks clone as :instance
- Propagates instance creation to sources
- Calls init if defined
Each call creates independent instance with separate state.
#instance? ⇒ Boolean Originally defined in module Series::Serie::Prototyping
Checks if serie is in instance state.
#lazy {|previous| ... } ⇒ LazySerieEval Originally defined in module Series::Operations
Delays evaluation to next step (lazy evaluation).
Block receives previous value and evaluates for current step. Enables state-dependent transformations.
#lock ⇒ Locker Originally defined in module Series::Operations
Locks serie preventing further modifications.
Returns locked copy that cannot be transformed further.
#map(isolate_values: nil) {|value| ... } ⇒ ProcessWith Originally defined in module Series::Operations
Maps values via transformation block.
Simplest and most common transformation. Applies block to each value.
Shorthand for with without additional series.
#max_size(length) ⇒ LengthLimiter Originally defined in module Series::Operations
Limits serie to maximum number of values.
Stops after N values regardless of source length.
#merge ⇒ MergeSerieOfSeries Originally defined in module Series::Operations
Merges serie of series into single serie.
Flattens one level: consumes serie where each element is itself a serie, merging them sequentially.
#multiplex(*indexed_series, **hash_series) ⇒ MultiplexSelector Originally defined in module Series::Operations
Advances every serie and gives back the value of the one selected.
All of them move, all of the time. What the selector chooses is which one is heard, not which one runs -- so this is a window onto several simultaneous streams, and looking away from one does not pause it. A crossfade, a texture where one layer surfaces at a time, an instrument that changes what it is doubling.
Compare #switch, where the unselected series wait.
#process_with(**parameters) {|value, parameters| ... } ⇒ Processor Originally defined in module Series::Operations
Transforms each value with a block whose parameters can change later.
When this is the answer, and not .map
.map { |v| v + 7 } freezes the 7 in the block. process_with keeps
it on the serie, where it can be changed while the serie is running
-- so the transformation is under control instead of being decided once.
A transposition that moves mid-phrase, a scaling driven from outside, a
depth that a controller sets: anything where the amount is itself a
parameter of the piece.
If the amount is known and fixed, .map says it with less.
#prototype ⇒ Serie Also known as: p Originally defined in module Series::Serie::Prototyping
Returns prototype of serie.
- If already prototype, returns self
- If instance, returns original prototype (if available)
- If undefined, raises PrototypingError
#prototype? ⇒ Boolean Originally defined in module Series::Serie::Prototyping
Checks if serie is in prototype state.
#proxy ⇒ Object Originally defined in module Series::Operations
TODO add test case
#quantize(reference: nil, step: nil, value_attribute: nil, stops: nil, predictive: nil, left_open: nil, right_open: nil) ⇒ RawQuantizer, PredictiveQuantizer Originally defined in module Series::Operations
Quantizes time-value serie to discrete steps.
Quantization Modes
- Raw: Rounds values to nearest step, interpolates between points
- Predictive: Predicts crossings of quantization boundaries
Applications
- Quantize MIDI controller data to discrete values
- Convert continuous pitch bends to semitones
- Snap timing to grid
- Generate stepped automation curves
- Convert analog input to digital steps
#queued ⇒ QueueSerie Originally defined in module Series::Operations
Wraps this serie in a queue.
#randomize(random: nil) ⇒ Randomizer Originally defined in module Series::Operations
Randomizes order of values.
Shuffles values randomly. Requires finite serie.
#remove(block = nil) {|value| ... } ⇒ Remover Originally defined in module Series::Operations
Removes values matching condition.
Filters out values where block returns true.
#repeat(times = nil, condition: nil) { ... } ⇒ Repeater, InfiniteRepeater Originally defined in module Series::Operations
Repeats serie multiple times or conditionally.
Three modes:
- times: Repeat exact number of times
- condition: Repeat while condition true
- neither: Infinite repetition
#reverse ⇒ Reverser Originally defined in module Series::Operations
Reverses order of values.
Consumes entire serie and returns values in reverse order. Requires finite serie.
#select(block = nil) {|value| ... } ⇒ Selector Originally defined in module Series::Operations
Selects values matching condition.
Keeps only values where block returns true.
#shift(shift) ⇒ Shifter Originally defined in module Series::Operations
Rotates serie elements circularly.
Performs circular rotation of elements:
- Negative values rotate left (first elements move to end)
- Positive values rotate right (last elements move to beginning)
- Zero performs no rotation
Note: Right rotation (positive values) requires finite series as the entire serie must be loaded into memory for rotation.
#skip(length) ⇒ Skipper Originally defined in module Series::Operations
Skips first N values.
Discards first length values, returns rest.
#split ⇒ Splitter Originally defined in module Series::Operations
Serie splitter for decomposing hash/array values into component series.
Splits series of hash or array values into individual component series, enabling independent access to each component.
Splitting Modes
- Hash mode: Split
{pitch: 60, velocity: 96}into separate series for:pitchand:velocity - Array mode: Split
[60, 96]into separate series for indices 0, 1
Component Access
- Hash:
splitter[:pitch],splitter[:velocity] - Array:
splitter[0],splitter[1] - Enumerable:
splitter.each { |component| ... }
Use Cases
- Separate polyphonic voices from single source
- Independent processing of musical parameters
- Extract specific components (pitch, duration, velocity, etc.)
- Multi-track decomposition
#state ⇒ Symbol Originally defined in module Series::Serie::Prototyping
Returns current state of serie.
Attempts to resolve undefined state from sources before returning. State is one of: :prototype, :instance, or :undefined.
#switch(*indexed_series, **hash_series) ⇒ Switcher Originally defined in module Series::Operations
Reads one value from whichever serie the selector names.
The unselected series do not advance. Each one waits where it was and continues from there next time it is chosen, which is what makes this a dialogue between materials rather than a window onto them: two voices taking turns, each picking up its own thread.
Compare #multiplex, where everything advances and only one value is heard.
#switch_serie(*indexed_series, **hash_series) ⇒ SwitchFullSerie Originally defined in module Series::Operations
Switches to entirely different series based on selector.
Changes which serie is being consumed entirely.
#undefined? ⇒ Boolean Originally defined in module Series::Serie::Prototyping
Checks if serie is in undefined state.
#union_timed(*other_timed_series, key: nil, **other_key_timed_series) ⇒ TimedUnionOfArrayOfTimedSeries, TimedUnionOfHashOfTimedSeries Originally defined in module Series::Operations
Combines this timed serie with others via TIMED_UNION.
Convenience method for unioning series, supporting both array and hash modes. Calls Constructors#TIMED_UNION constructor with appropriate parameters.
Array mode: s1.union_timed(s2, s3)
Hash mode: s1.union_timed(key: :melody, bass: s2, drums: s3)
#with(*with_series, on_restart: nil, isolate_values: nil, **with_key_series) {|main_value, with_values, with_key_values| ... } ⇒ With Also known as: eval Originally defined in module Series::Operations
Combines multiple series for mapping.
Synchronously iterates multiple series, passing all values to block. Enables multi-voice transformations and combinations.
Parameters
- with_series: Positional series (passed as array to block)
- with_key_series: Named series (passed as keywords to block)
- on_restart: Block called on restart
- isolate_values: Clone values to prevent mutation
Block Parameters
Block receives:
- Main serie value (first argument)
- Positional with_series values (array)
- Keyword with_key_series values (keywords)