How to use the scamp.utilities.SavesToJSON function in scamp

To help you get started, we’ve selected a few scamp examples, based on popular ways it is used in public projects.

Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.

github MarcTheSpark / scamp / scamp / _note_properties.py View on Github external
elif character == "{":
            curly_count += 1
        elif character == ")":
            paren_count -= 1
        elif character == "]":
            square_count -= 1
        elif character == "}":
            curly_count -= 1
        elif character == "," and paren_count == square_count == curly_count == 0:
            out.append(s[last_split:i-1].strip())
            last_split = i
    out.append(s[last_split:].strip())
    return out


class NotePropertiesDictionary(UserDict, SavesToJSON):

    def __init__(self, **kwargs):
        NotePropertiesDictionary._standardize_plural_entry("articulations", kwargs)
        NotePropertiesDictionary._standardize_plural_entry("noteheads", kwargs)
        if len(kwargs["noteheads"]) == 0:
            kwargs["noteheads"] = ["normal"]
        NotePropertiesDictionary._standardize_plural_entry("notations", kwargs)
        NotePropertiesDictionary._standardize_plural_entry("texts", kwargs)
        NotePropertiesDictionary._standardize_plural_entry("playback_adjustments", kwargs)

        for i, adjustment in enumerate(kwargs["playback_adjustments"]):
            if isinstance(adjustment, str):
                kwargs["playback_adjustments"][i] = NotePlaybackAdjustment.from_string(adjustment)

        if "spelling_policy" not in kwargs:
            kwargs["spelling_policy"] = None
github MarcTheSpark / scamp / misc / old / old_settings.py View on Github external
# - if "split", the note is split rhythmically at the control points
    # - if "none", control points are ignored
    "control_point_policy": "split",
    # if true, we consider all control points in the engraving process. If false, we only consider local extrema.
    "consider_non_extrema_control_points": False,
    # if true, the final pitch reached is expressed as a gliss up to a headless grace note
    "include_end_grace_note": True,
    # this threshold helps determine which gliss control points are worth expressing in notation
    # the further a control point is from its neighbors, and the further it deviates from
    # the linearly interpolated pitch at that point, the higher its relevance score.
    "inner_grace_relevance_threshold": 4.0,
    "max_inner_graces_music_xml": 1
}


class GlissandiEngravingSettings(SavesToJSON):

    def __init__(self, **settings):
        self._control_point_policy = _glissandi_engraving_factory_defaults["control_point_policy"] \
            if "control_point_policy" not in settings else settings["control_point_policy"]
        try:
            assert self.control_point_policy in ("grace", "split", "none")
        except AssertionError:
            logging.warning("Control point policy must be one of: \"grace\", \"split\", or \"none\". Defaulting "
                            "to \"{}\".".format(_glissandi_engraving_factory_defaults["control_point_policy"]))
            self.control_point_policy = _glissandi_engraving_factory_defaults["control_point_policy"]
        self.consider_non_extrema_control_points = \
            _glissandi_engraving_factory_defaults["consider_non_extrema_control_points"] \
            if "consider_non_extrema_control_points" not in settings \
                else settings["consider_non_extrema_control_points"]
        self.include_end_grace_note = _glissandi_engraving_factory_defaults["include_end_grace_note"] \
            if "include_end_grace_note" not in settings else settings["include_end_grace_note"]
github MarcTheSpark / scamp / scamp / session.py View on Github external
from .transcriber import Transcriber
from ._midi import get_available_midi_input_devices, get_port_number_of_midi_device, \
    print_available_midi_input_devices, print_available_midi_output_devices, start_midi_listener
from .instruments import Ensemble, ScampInstrument
from clockblocks import Clock, current_clock
from .utilities import SavesToJSON
from ._dependencies import pynput, pythonosc
from threading import Thread, current_thread
from .spelling import SpellingPolicy
from typing import Union, Tuple, Iterator, Callable, Sequence
from .performance import Performance
import threading


class Session(Clock, Ensemble, Transcriber, SavesToJSON):
    """
    A Session combines the functionality of a master Clock, an Ensemble, and a Transcriber.
    Since it's a master Clock, it manages global tempo; since it's an Ensemble, you use it to create and keep
    track of instruments, and since it's a Transcriber, it allows you to transcribe and generate notation from what
    the instruments are playing. You can also use a Session to set up interactive callbacks for MIDI, OSC, mouse
    events, and keyboard events.

    :param tempo: the initial tempo of the master clock
    :param default_soundfont: the default soundfont used by instruments in this session. (Can be overridden at
        instrument creation.)
    :param default_audio_driver: the default driver used by (soundfont) instruments to output audio. (Can be
        overridden at instrument creation.)
    :param default_midi_output_device: the default midi_output_device (by name or port number) for outgoing midi
        streams. (Again, can be overridden at instrument creation.)
    """
github MarcTheSpark / scamp / scamp / playback_adjustments.py View on Github external
# for instance, if param_value is a Envelope, multiply is zero and add is a Envelope,
        # you would end up trying to add two Envelopes, which we don't allow
        return self.add if self.multiply == 0 else param_value * self.multiply + self.add

    def _to_dict(self):
        return self.__dict__

    @classmethod
    def _from_dict(cls, json_dict):
        return cls(**json_dict)

    def __repr__(self):
        return "ParamPlaybackAdjustment({}, {})".format(self.multiply, self.add)


class NotePlaybackAdjustment(SavesToJSON):

    """
    Represents an adjustment to the pitch, volume and/or length of the playback of a single note

    :param pitch_adjustment: The desired adjustment for the note's pitch. (None indicates no adjustment)
    :param volume_adjustment: The desired adjustment for the note's volume. (None indicates no adjustment)
    :param length_adjustment: The desired adjustment for the note's length. (None indicates no adjustment)
    :ivar pitch_adjustment: The desired adjustment for the note's pitch. (None indicates no adjustment)
    :ivar volume_adjustment: The desired adjustment for the note's volume. (None indicates no adjustment)
    :ivar length_adjustment: The desired adjustment for the note's length. (None indicates no adjustment)
    """

    def __init__(self, pitch_adjustment: ParamPlaybackAdjustment = None,
                 volume_adjustment: ParamPlaybackAdjustment = None,
                 length_adjustment: ParamPlaybackAdjustment = None):
        self.pitch_adjustment: ParamPlaybackAdjustment = pitch_adjustment
github MarcTheSpark / scamp / scamp / instruments.py View on Github external
    @classmethod
    def _from_dict(cls, json_dict):
        ensemble = cls(**json_dict)
        for instrument in ensemble.instruments:
            instrument.set_ensemble(ensemble)
        return ensemble

    def __str__(self):
        return "Ensemble({})".format(self.instruments)

    def __repr__(self):
        return "Ensemble._from_dict({})".format(self._to_dict())


class ScampInstrument(SavesToJSON):

    """
    Instrument class that does the playing of the notes. Generally this will be created through one of the
    "new_part" methods of the Session or Ensemble class.

    :param name: name of this instrument (e.g. when printed in a score)
    :param ensemble: Ensemble to which this instrument will belong.
    :param default_spelling_policy: sets :attr:`ScampInstrument.default_spelling_policy`
    :param clef_preference: sets :attr:`ScampInstrument.clef_preference`
    :ivar name: name of this instrument (e.g. when printed in a score)
    :ivar name_count: when there are multiple instruments of the same name within an Ensemble, this variable assigns
        each a unique index (starting with 0), to distinguish them
    :ivar ensemble: Ensemble to which this instrument will belong.
    :ivar playback_implementations: list of PlaybackImplementation(s) used to actually playback notes
    """
github MarcTheSpark / scamp / misc / old / old_settings.py View on Github external
"end_note": "end_note",
        "change_pitch": "change_pitch",
        "change_volume": "change_volume",
        "change_quality": "change_quality"
    },
    "adjustments": PlaybackDictionary(articulations={
        "staccato": NotePlaybackAdjustment.scale_params(length_scale=0.5),
        "staccatissimo": NotePlaybackAdjustment.scale_params(length_scale=0.3),
        "tenuto": NotePlaybackAdjustment.scale_params(length_scale=1.2),
        "accent": NotePlaybackAdjustment.scale_params(volume_scale=1.2),
        "marcato": NotePlaybackAdjustment.scale_params(volume_scale=1.5),
    })
}


class PlaybackSettings(SavesToJSON):

    def __init__(self, **settings):
        self.named_soundfonts = _playback_settings_factory_defaults["named_soundfonts"] \
            if "named_soundfonts" not in settings else settings["named_soundfonts"]
        self.default_audio_driver = _playback_settings_factory_defaults["default_audio_driver"] \
            if "default_audio_driver" not in settings else settings["default_audio_driver"]
        self.default_midi_output_device = _playback_settings_factory_defaults["default_midi_output_device"] \
            if "default_midi_output_device" not in settings else settings["default_midi_output_device"]
        self.default_max_midi_pitch_bend = _playback_settings_factory_defaults["default_max_midi_pitch_bend"] \
            if "default_max_midi_pitch_bend" not in settings else settings["default_max_midi_pitch_bend"]
        self.osc_message_addresses = _playback_settings_factory_defaults["osc_message_addresses"] \
            if "osc_message_addresses" not in settings else settings["osc_message_addresses"]
        self.adjustments = _playback_settings_factory_defaults["adjustments"] \
            if "adjustments" not in settings else settings["adjustments"]

    def restore_factory_defaults(self):
github MarcTheSpark / scamp / scamp / _soundfont_host.py View on Github external
from .utilities import resolve_relative_path, SavesToJSON, get_average_square_correlation
from .settings import playback_settings
from ._dependencies import fluidsynth, Sf2File
import logging
from collections import OrderedDict
import re
import os.path


class SoundfontHost(SavesToJSON):

    def __init__(self, soundfonts=(), audio_driver="default"):
        """
        A SoundfontHost hosts an instance of fluidsynth with one or several soundfonts loaded.
        It can be called upon to add or remove instruments from that synth

        :param soundfonts: one or several soundfonts to be loaded
        :param audio_driver: the audio driver to use
        """
        if isinstance(soundfonts, str):
            soundfonts = (soundfonts, )

        if fluidsynth is None:
            raise ModuleNotFoundError("FluidSynth not available.")

        self.audio_driver = playback_settings.default_audio_driver if audio_driver == "default" else audio_driver
github MarcTheSpark / scamp / scamp / playback_adjustments.py View on Github external
elif character == "{":
            curly_count += 1
        elif character == ")":
            paren_count -= 1
        elif character == "]":
            square_count -= 1
        elif character == "}":
            curly_count -= 1
        elif character == " " and paren_count == square_count == curly_count == 0:
            out.append(s[last_split:i-1].strip())
            last_split = i
    out.append(s[last_split:].strip())
    return out


class ParamPlaybackAdjustment(SavesToJSON):

    """
    Represents a multiply/add playback adjustment to a single parameter.
    (The multiply happens first, then the add.

    :param multiply: how much to multiply by
    :param add: how much to add
    :ivar multiply: how much to multiply by
    :ivar add: how much to add
    """

    def __init__(self, multiply: float = 1, add: float = 0):
        self.multiply = multiply
        self.add = add

    @classmethod
github MarcTheSpark / scamp / scamp / playback_implementations.py View on Github external
from ._dependencies import pythonosc
from typing import Tuple, Optional
import logging
from .settings import playback_settings
from .utilities import SavesToJSON, SavesToJSONMeta


class _PlaybackImplementationMeta(SavesToJSONMeta):

    def __call__(cls, *args, **kwargs):
        instance = super().__call__(*args, **kwargs)
        instance._try_to_bind_host_instrument()
        return instance


class PlaybackImplementation(SavesToJSON, metaclass=_PlaybackImplementationMeta):

    """
    Abstract base class for playback implementations, which do the actual work of playback, either by playing sounds or
    by sending messages to external synthesizers to play sounds.

    :param host_instrument: The :class:`~scamp.instruments.ScampInstrument` that will use this playback implementation
        for playback. When this PlaybackImplementation is constructed, it is automatically added to the list of
        PlaybackImplementations that the host instrument uses.
    """

    def __init__(self, host_instrument: 'instruments_module.ScampInstrument'):
        # this is a fallback: if the instrument does not belong to an ensemble, it does not have
        # shared resources and so it will rely on its own privately held resources.
        self._resources = None
        self._host_instrument = host_instrument
        # This are set when the host instrument is set
github MarcTheSpark / scamp / scamp / performance_note.py View on Github external
import itertools
from copy import deepcopy
from functools import total_ordering

from expenvelope import Envelope
from .utilities import SavesToJSON
from ._note_properties import NotePropertiesDictionary
from .settings import engraving_settings


@total_ordering
class PerformanceNote(SavesToJSON):

    def __init__(self, start_time, length, pitch, volume, properties):
        """
        Represents a single note played by a ScampInstrument

        :param start_time: the start beat of the
        :type start_time: float
        :param length: the length of the note in beats (either a float or a list of floats representing tied segments)
        :param pitch: the pitch of the note (float or Envelope)
        :param volume: the volume of the note (float or Envelope)
        :param properties: dictionary of note properties, or string representing those properties
        """
        self.start_time = start_time
        # if length is a tuple, this indicates that the note is to be split into tied segments
        self.length = length
        # if pitch is a tuple, this indicates a chord