require_relative 'processor' module SSMD::Processors class ProsodyProcessor < Processor def result with_volume || with_rate || with_pitch end def regex Regex.prosody end private def with_volume name, text = volume_keys.map { |k| [k, match[k]] }.find { |k, v| !v.nil? } "#{text}" if name && text end def with_rate name, text = rate_keys.map { |k| [k, match[k]] }.find { |k, v| !v.nil? } "#{text}" if name && text end def with_pitch name, text = pitch_keys.map { |k| [k, match[k]] }.find { |k, v| !v.nil? } "#{text}" if name && text end def volume_keys ['silent', 'x-soft', 'soft', 'loud', 'x-loud'] end def rate_keys ['x-slow', 'slow', 'fast', 'x-fast'] end def pitch_keys ['x-low', 'low', 'high', 'x-high'] end module Regex module_function def prosody %r{ (?:#{slow_rate}) | (?:#{fast_rate}) | (?:#{silent_volume}) | (?:#{soft_volume}) | (?:#{loud_volume}) | (?:#{low_pitch}) | (?:#{high_pitch}) }x end ## # Match example: ~silent~ def silent_volume /#{ws_start}~#{content('silent')}~#{ws_end}/ end ## # Match example: --extra soft-- or -soft- def soft_volume /(?:#{ws_start}--#{content('x-soft')}--#{ws_end})|(?:#{ws_start}-#{content('soft')}-#{ws_end})/ end ## # Match example: ++extra loud or +loud+ def loud_volume /(?:#{ws_start}\+\+#{content('x-loud')}\+\+#{ws_end})|(?:#{ws_start}\+#{content('loud')}\+#{ws_end})/ end ## # Match example: <>extra fast>> or >fast> def fast_rate /(?:#{ws_start}>>#{content('x-fast')}>>#{ws_end})|(?:#{ws_start}>#{content('fast')}>#{ws_end})/ end ## # Match example: __extra low__ or _low_ def low_pitch /(?:#{ws_start}__#{content('x-low')}__#{ws_end})|(?:#{ws_start}_#{content('low')}_#{ws_end})/ end ## # Match example: ^^extra high^^ or ^high^ def high_pitch /(?:#{ws_start}\^\^#{content('x-high')}\^\^#{ws_end})|(?:#{ws_start}\^#{content('high')}\^#{ws_end})/ end ## # Matches either a single char or a longer string starting and ending # with a non-whitespace char. def content(name = nil) id = name ? "?<#{name}>" : "" /(#{id}(?:[^\s])|(?:[^\s].*[^\s]))/ end ## # Matches the beginning of the input or a whitespace char via lookbehind, # meaning it's excluded from the match result. def ws_start /(?<=(\A)|(?:\s))/ end ## # Matches the end of the input or a whitespace char via lookahead, # meaning it's excluded from the match result. def ws_end /(?=(\Z)|(?:\s))/ end end end end