def ks_synth(freq): """ Synthesize the given frequency into a Stream by using a model based on Karplus-Strong. """ ks_mem = (sum(lz.sinusoid(x * freq) for x in [1, 3, 9]) + lz.white_noise() + lz.Stream(-1, 1)) / 5 return lz.karplus_strong(freq, memory=ks_mem)
def m21_to_stream(score, synth=ks_synth, beat=90, fdur=2., pad_dur=.5, rate=lz.DEFAULT_SAMPLE_RATE): """ Converts Music21 data to a Stream object. Parameters ---------- score : A Music21 data, usually a music21.stream.Score instance. synth : A function that receives a frequency as input and should yield a Stream instance with the note being played. beat : The BPM (beats per minute) value to be used in playing. fdur : Relative duration of a fermata. For example, 1.0 ignores the fermata, and 2.0 (default) doubles its duration. pad_dur : Duration in seconds, but not multiplied by ``s``, to be used as a zero-padding ending event (avoids clicks at the end when playing). rate : The sample rate, given in samples per second. """ # Configuration s, Hz = lz.sHz(rate) step = 60. / beat * s # Creates a score from the music21 data score = reduce( operator.concat, [ [ ( pitch.frequency * Hz, # Note note.offset * step, # Starting time note.quarterLength * step, # Duration Fermata in note.expressions) for pitch in note.pitches ] for note in score.flat.notes ]) # Mix all notes into song song = lz.Streamix() last_start = 0 for freq, start, dur, has_fermata in score: delta = start - last_start if has_fermata: delta *= 2 song.add(delta, synth(freq).limit(dur)) last_start = start # Zero-padding and finishing song.add(dur + pad_dur * s, lz.Stream([])) return song
def splitter(lines, sep="-=", keep_idx=False): """ Splits underlined blocks without indentation (reStructuredText pattern). Parameters ---------- lines : A list of strings sep : Underline symbols. A line with only such symbols will be seen as a underlined one. keep_idx : If False (default), the function returns a collections.OrderedDict. Else, returns a list of index pairs Returns ------- A collections.OrderedDict instance where a block with underlined key like ``"Key\\n==="`` and a list of lines following will have the item (key, list of lines), in the order that they appeared in the lists input. Empty keys gets an order numbering, and might happen for example after a ``"----"`` separator. The values (lists of lines) don't include the key nor its underline, and is also stripped/trimmed as lines (i.e., there's no empty line as the first and last list items, but first and last line may start/end with whitespaces). """ separators = audiolazy.Stream( idx - 1 for idx, el in enumerate(lines) if all(char in sep for char in el) and len(el) > 0 ).append([len(lines)]) first_idx = separators.copy().take() blk_data = OrderedDict() empty_count = iter(audiolazy.count(1)) next_empty = lambda: "--Empty--{0}--".format(next(empty_count)) if first_idx != 0: blk_data[next_empty()] = lines[:first_idx] for idx1, idx2 in separators.blocks(size=2, hop=1): name = lines[idx1].strip() if lines[idx1].strip() != "" else next_empty() blk_data[name] = lines[idx1+2 : idx2] # Strips the empty lines for name in blk_data: while blk_data[name][-1].strip() == "": blk_data[name].pop() while blk_data[name][0].strip() == "": blk_data[name] = blk_data[name][1:] return blk_data
def pre_processor(app, what, name, obj, options, lines, namer=lambda name: ":obj:`{0}`".format(name)): """ Callback preprocessor function for docstrings. Converts data from Spyder pattern to Sphinx, using a ``namer`` function that defaults to ``lambda name: ":obj:`{0}`".format(name)`` (specific for ``.. seealso::``). """ # Duplication removal if what == "module": # For some reason, summary appears twice idxs = [idx for idx, el in enumerate(lines) if el.startswith("Summary")] if len(idxs) >= 2: del lines[idxs.pop():] # Remove the last summary if len(idxs) >= 1: lines.insert(idxs[-1] + 1, "") if obj is audiolazy.lazy_math: lines.insert(idxs[-1] + 1, ".. tabularcolumns:: cl") else: lines.insert(idxs[-1] + 1, ".. tabularcolumns:: CJ") lines.insert(idxs[-1] + 1, "") # Real docstring format pre-processing result = [] for name, blk in iteritems(splitter(lines)): nlower = name.lower() if nlower == "parameters": starters = audiolazy.Stream(idx for idx, el in enumerate(blk) if len(el) > 0 and not el.startswith(" ") ).append([len(blk)]) for idx1, idx2 in starters.blocks(size=2, hop=1): param_data = " ".join(b.strip() for b in blk[idx1:idx2]) param, expl = param_data.split(":", 1) if "," in param: param = param.strip() if not param[0] in ("(", "[", "<", "{"): param = "[{0}]".format(param) while "," in param: fparam, param = param.split(",", 1) result.append(":param {0}: {1}".format(fparam.strip(), "\.\.\.")) result.append(":param {0}: {1}".format(param.strip(), expl.strip())) elif nlower == "returns": result.append(":returns: " + " ".join(blk)) elif nlower in ("note", "warning", "hint"): result.append(".. {0}::".format(nlower)) result.extend(" " + el for el in blk) elif nlower == "examples": result.append("**Examples**:") result.extend(" " + el for el in blk) elif nlower == "see also": result.append(".. seealso::") for el in blk: if el.endswith(":"): result.append("") # Skip a line # Sphinx may need help here to find some object locations refs = [namer(f.strip()) for f in el[:-1].split(",")] result.append(" " + ", ".join(refs)) else: result.append(" " + el) else: # Unkown block name, perhaps the starting one (empty) result.extend(blk) # Skip a line after each block result.append("") # Replace lines with the processed data while keeping the actual lines id del lines[:] lines.extend(result)