Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def __init__(self, host_instrument: 'instruments_module.ScampInstrument', midi_output_device: str = "default",
num_channels=8, midi_output_name: Optional[str] = None, max_pitch_bend: int = "default",
note_on_and_off_only: bool = False):
super().__init__(host_instrument, num_channels, note_on_and_off_only)
# we hold onto these arguments for the purposes of json serialization
# note that if the midi_output_device or midi_output_name said "default",
# then we save it as "default", rather than what that default resolved to.
self.num_channels = num_channels
self.midi_output_device = midi_output_device
self.midi_output_name = midi_output_name
midi_output_device = playback_settings.default_midi_output_device if midi_output_device == "default" \
else midi_output_device
if midi_output_name is None:
# if no midi output name is given, fall back to the instrument name
# if the instrument has no name, fall back to "Unnamed"
midi_output_name = "Unnamed" if host_instrument.name is None else host_instrument.name
# since rtmidi can only have 16 output channels, we need to create several output devices if we are using more
if num_channels <= 16:
self.rt_simple_outs = [SimpleRtMidiOut(midi_output_device, midi_output_name)]
else:
self.rt_simple_outs = [
SimpleRtMidiOut(midi_output_device, midi_output_name + " chans {}-{}".format(chan, chan + 15))
for chan in range(0, num_channels, 16)
]
self.max_pitch_bend = None
def __init__(self, host_instrument: 'instruments_module.ScampInstrument', bank_and_preset: Tuple[int, int] = (0, 0),
soundfont: str = "default", num_channels: int = 8, audio_driver: str = "default",
max_pitch_bend: int = "default", note_on_and_off_only: bool = False):
super().__init__(host_instrument, num_channels, note_on_and_off_only)
# we hold onto these arguments for the purposes of json serialization
# note that if the audio_driver said "default", then we save it as "default",
# rather than what that default resolved to.
self.audio_driver = audio_driver
self.bank_and_preset = bank_and_preset
self.max_pitch_bend = max_pitch_bend
self.soundfont = playback_settings.default_soundfont if soundfont == "default" else soundfont
# these are setup by the `_initialize_shared_resources` function
self.soundfont_host = self.soundfont_instrument = None
from .settings import playback_settings
import logging
import os
import platform
ABJAD_MINIMUM_VERSION = "3.1"
try:
if playback_settings.try_system_fluidsynth_first:
# first choice: import using an installed version of pyfluidsynth
logging.debug("Trying to load system copy of pyfluidsynth.")
import fluidsynth
else:
# first choice: use the use the local, tweaked copy of pyfluidsynth (which will also try to
# load up a local copy of the fluidsynth dll on Windows or dylib on MacOS)
logging.debug("Trying to copy of pyfluidsynth from within SCAMP package.")
from ._thirdparty import fluidsynth
logging.debug("Loading of pyfluidsynth succeeded.")
except (ImportError, AttributeError):
logging.debug("Loading of pyfluidsynth failed.")
try:
if playback_settings.try_system_fluidsynth_first:
# second choice: use the use the local, tweaked copy of pyfluidsynth (which will also try to
# load up a local copy of the fluidsynth dll on Windows or dylib on MacOS)
logging.debug("Trying to copy of pyfluidsynth from within SCAMP package.")
logging.debug("Loading of pyfluidsynth succeeded.")
except (ImportError, AttributeError):
# if we're here, it's probably because fluidsynth wasn't installed
logging.debug("Loading of pyfluidsynth failed again.")
fluidsynth = None
logging.warning("Fluidsynth could not be loaded; synth output will not be available.")
if fluidsynth is not None and playback_settings.default_audio_driver == "auto":
print("Testing for working audio driver...")
found_driver = False
for driver in ['alsa', 'coreaudio', 'dsound', 'Direct Sound', 'oss', 'pulseaudio', 'jack', 'portaudio', 'sndmgr']:
test_synth = fluidsynth.Synth()
test_synth.start(driver=driver)
if test_synth.audio_driver is not None:
playback_settings.default_audio_driver = driver
playback_settings.make_persistent()
found_driver = True
test_synth.delete()
print("Found audio driver '{}'. This has been made the default, but it can be altered via "
"the playback settings.".format(driver))
break
test_synth.delete()
if not found_driver:
logging.warning("No working audio driver was found; synth output will not be available.")
try:
from sf2utils.sf2parse import Sf2File
except ImportError:
Sf2File = None
logging.warning("sf2utils was not found; info about soundfont presets will not be available.")
try:
def resolve_soundfont_path(soundfont: str):
"""
Consults playback settings and returns the path to the given soundfont
:param soundfont: either the name of a named soundfont or an explicit soundfont path. Paths are resolved relatively
unless they start with a slash.
:return: an absolute path to the soundfont
"""
soundfont_path = playback_settings.named_soundfonts[soundfont] \
if soundfont in playback_settings.named_soundfonts else soundfont
if soundfont_path.startswith("/"):
# Absolute soundfont path
return soundfont_path
elif soundfont_path.startswith("~/"):
# Relative to user home directory
return os.path.expanduser(soundfont_path)
else:
# Relative to one of the search paths defined in the settings
for search_path in playback_settings.soundfont_search_paths:
if search_path.startswith("~/"):
search_path = os.path.expanduser(search_path)
if not search_path.startswith("/"):
search_path = resolve_relative_path(search_path)
try:
if playback_settings.try_system_fluidsynth_first:
# first choice: import using an installed version of pyfluidsynth
logging.debug("Trying to load system copy of pyfluidsynth.")
import fluidsynth
else:
# first choice: use the use the local, tweaked copy of pyfluidsynth (which will also try to
# load up a local copy of the fluidsynth dll on Windows or dylib on MacOS)
logging.debug("Trying to copy of pyfluidsynth from within SCAMP package.")
from ._thirdparty import fluidsynth
logging.debug("Loading of pyfluidsynth succeeded.")
except (ImportError, AttributeError):
logging.debug("Loading of pyfluidsynth failed.")
try:
if playback_settings.try_system_fluidsynth_first:
# second choice: use the use the local, tweaked copy of pyfluidsynth (which will also try to
# load up a local copy of the fluidsynth dll on Windows or dylib on MacOS)
logging.debug("Trying to copy of pyfluidsynth from within SCAMP package.")
from ._thirdparty import fluidsynth
else:
# second choice: import using an installed version of pyfluidsynth
logging.debug("Trying to load system copy of pyfluidsynth.")
import fluidsynth
logging.debug("Loading of pyfluidsynth succeeded.")
except (ImportError, AttributeError):
# if we're here, it's probably because fluidsynth wasn't installed
logging.debug("Loading of pyfluidsynth failed again.")
fluidsynth = None
logging.warning("Fluidsynth could not be loaded; synth output will not be available.")
if fluidsynth is not None and playback_settings.default_audio_driver == "auto":
def get_soundfont_presets(which_soundfont="default"):
which_soundfont = playback_settings.default_soundfont if which_soundfont == "default" else which_soundfont
soundfont_path = resolve_soundfont_path(which_soundfont)
if Sf2File is None:
raise ModuleNotFoundError("Cannot inspect soundfont presets; please install sf2utils.")
# if we have sf2utils, load up the preset info from the soundfonts
with open(soundfont_path, "rb") as sf2_file:
sf2 = Sf2File(sf2_file)
return sf2.presets
def __init__(self, host_instrument: 'instruments_module.ScampInstrument', port: int, ip_address: str = "127.0.0.1",
message_prefix: Optional[str] = None, osc_message_addresses: dict = "default"):
super().__init__(host_instrument)
# the output client for OSC messages
# by default the IP address is the local 127.0.0.1
self.ip_address = ip_address
self.port = port
self.client = pythonosc.udp_client.SimpleUDPClient(ip_address, port)
# the first part of the osc message; used to distinguish between instruments
# by default uses the name of the instrument with spaces removed
self.message_prefix = message_prefix if message_prefix is not None \
else (self._host_instrument.name.replace(" ", "") if self._host_instrument.name is not None else "unnamed")
self.osc_message_addresses = playback_settings.osc_message_addresses
if osc_message_addresses != "default":
assert isinstance(osc_message_addresses, dict), "osc_message_addresses argument must be a complete or " \
"incomplete dictionary of alternate osc messages"
# for each type of osc message, use the one specified in the osc_message_addresses argument if available,
# falling back to the one in playback_settings if it's not available
self.osc_message_addresses = {key: osc_message_addresses[key] if key in osc_message_addresses else value
for key, value in playback_settings.osc_message_addresses.items()}
self._currently_playing = []
def clean_up():
for note_id in list(self._currently_playing):
self.end_note(note_id)
atexit.register(clean_up)
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
self.synth = fluidsynth.Synth()
self.synth.start(driver=self.audio_driver)
self.used_channels = 0 # how many channels have we already assigned to various instruments
self.soundfont_ids = OrderedDict() # mapping from soundfont names to the fluidsynth ids of loaded soundfonts
self.soundfont_instrument_lists = {}
for soundfont in soundfonts:
self.load_soundfont(soundfont)
length_segments = length
length = sum(length)
else:
length_segments = None
did_an_adjustment = False
# first apply all of the explicit playback adjustments
for adjustment in self.playback_adjustments:
assert isinstance(adjustment, NotePlaybackAdjustment)
pitch, volume, length = adjustment.adjust_parameters(pitch, volume, length)
did_an_adjustment = True
if include_notation_derived:
for notation_category in ["articulations", "noteheads", "notations"]:
for applied_notation in self[notation_category]:
notation_derived_adjustment = playback_settings.adjustments.get(applied_notation)
if notation_derived_adjustment is not None:
assert isinstance(notation_derived_adjustment, NotePlaybackAdjustment)
pitch, volume, length = notation_derived_adjustment.adjust_parameters(pitch, volume, length)
did_an_adjustment = True
# Having made the adjustment, if the length was a tuple of adjoined segments, we now go back
# and scale those according to the adjustment made to length
if length_segments is not None:
length_scale_factor = length / sum(length_segments)
length = length_segments if length_scale_factor == 1 else \
tuple(segment_length * length_scale_factor for segment_length in length_segments)
return pitch, volume, length, did_an_adjustment