def sd_select_device(device_type='in'): """ type: in or out returns [index, name] of device """ info_title("Devices by index ({0} found):".format(len(sd.query_devices()))) for i in str(sd.query_devices()).split('\n'): info_line(i) while True: p("Enter desired device index") device_ind = inpt('int') try: device = sd.query_devices()[device_ind] except IndexError: err_mess("No device with index {0}".format(device_ind)) continue if device_type in ('in', 'input'): if device['max_input_channels'] < 1: err_mess("Device cannot be used as an input") continue elif device_type in ('out', 'output'): if device['max_output_channels'] < 1: err_mess("Device cannot be used as an output") device_name = device['name'] info_block("'{0}' selected".format(device_name)) return [device_ind, device_name]
def show(self): """ like repr but prints directly """ info_line("Sourced from {0} '{1}':".format(self.s_type, self.s_name)) for k, v in self.s_info.items(): info_list("{0}: {1}".format(k, v))
def info(self): """ cat: info """ info_block("{0} '{1}'".format(self.reltype, self.name)) info_line("Stored at '{0}'".format(self.path)) info_line("Samplerate: {0}".format(self.rate)) self.list_children()
def save_audio(self): """ base wav audio saving. requires 'rate' and 'arr' attributes """ info_block("saving audio of {0} '{1}'...".format( self.reltype, self.name)) if self.arr is None: info_line("no audio to save...") else: sf.write(self.get_audiofile_fullpath(), self.arr, self.rate.magnitude)
def add_marker(self, sample_ind, marker): """ method to be called by add() process """ if isinstance(sample_ind, Units.Quant): sample_ind = sample_ind.magnitude try: replaced = self.markers[sample_ind] info_line("Replacing marker '{0}' with '{1}'".format( replaced, marker)) except KeyError: info_line("Added marker '{0}'".format(marker)) self.markers[sample_ind] = marker
def info(self): """ desc: display this objects data cat: info dev: essentially just an expanded repr. repr is also defined in super() """ info_block("{0} '{1}'".format(self.reltype, self.name)) info_line("sourced from {0}: {1}".format(self.source_block[0], self.source_block[1])) for ind in range(1, len(self.source_block) // 2): print(" {0}: {1}".format(self.source_block[2 * ind], self.source_block[2 * ind + 1])) info_line("parent: {0}".format(self.parent)) info_line("rate: {0}".format(self.rate)) info_line("size: {0:.4f}, {1:,}".format(self.size_secs(), self.size_samps())) info_line("pan: {0}".format(self.pan_val))
def start(self): for samp_ind in range(len(self.arr)): if samp_ind % self.parent.rate == 0: info_line("{0} seconds computed".format(samp_ind / self.parent.rate)) samp = self.arr[samp_ind] for n in self.other_nodes: if n[0].purpose != 'listener': # n as [node, angle, dist] pan = angle_to_pan(n[1]) * self.parent.spread samp_val = (samp[0] * (1 - pan)) + (samp[1] * (1 + pan)) offset = int(n[2] / 343 * self.parent.rate) + samp_ind n[0].bounce(samp_val, n[1], offset)
def see_proj(self, proj_name, proj_path): info_block("Previewing Project '{0}'".format(proj_name)) fullpath = join_path( proj_path, proj_name + ".Project." + RelSavedObj.datafile_extension) with open(fullpath, "r") as f: data = json.load(f) info_title("Path: " + data["path"]) info_line("Audio file: " + str(data["file"])) info_line("Children:") children = [ re.sub(r"<.*>", "", i).split(".") for i in data["children"] ] children = ["{0} '{1}'".format(i[1], i[0]) for i in children] info_list(children)
def info(self): """ cat: info """ section_head("{0} '{1}'".format(self.reltype, self.name)) info_line("{0} samples".format(len(self.smps))) info_line("{0} rhythms".format(len(self.rhythms))) info_line("{0} active pairs".format(len(self.active))) info_line("(use list_samples/rhythms/active to view them)")
def delete(self, location): """ cat: edit desc: delete a marker from this controller args: location: beat or sec of the marker to remove """ beatsec = inpt_validate(location, self.time_units, allowed=self.time_allowed) sample_ind = beatsec.to_samps() try: marker = self.markers[sample_ind] info_line("Deleting marker '{0}'".format(marker)) del self.markers[sample_ind] except KeyError: err_mess("No marker to delete at {0}".format(beatsec))
def read_file(self, file_path=None): """ reads files for recording object init takes multiple formats (via PyDub and Soundfile) updates self.source, self.arr, self.rate """ if file_path is None: print(" Choose an input sound file...") time.sleep(1) file_path = input_file() info_block("Reading audio file...") t1 = time.time() # Handling file types _, _, ext = split_path(file_path) if ext != "wav": try: not_wav = pd.from_file(file_path, file_path.ext) not_wav.export(".temp_soundfile.wav", format="wav") file_path = ".temp_soundfile.wav" except FileNotFoundError: print(" > unable to find file '{0}'".format(file_path)) print(" > make sure to include .wav/.mp3/etc extension") return self.read_file() # self.source_block["file"] = file_path # Reading and Processing File try: self.arr, rate = sf.read(file_path) self.rate = Units.rate(rate) except RuntimeError: print( " > unable to find or read '{0}'. Is that the correct extension?" .format(file_path)) return self.read_file() try: os.remove(".temp_soundfile.wav") except FileNotFoundError: pass if len(self.arr.shape) < 2: self.arr = NpOps.stereoify(self.arr) t2 = time.time() info_line( "sound file '{0}' read successfully in {1:.4f} seconds".format( file_path, t2 - t1))
def __init__(self, name, reltype, mode, **kwargs): super().__init__(name=name, reltype=reltype, **kwargs) if mode == "create": section_head("Initializing {0}".format(reltype)) elif mode == "load": info_line("Loading {0} '{1}'".format(reltype, name)) elif mode == "prop": # property pass else: raise UnexpectedIssue("Unknown mode '{0}'".format(mode)) self.name = name self.reltype = reltype self._do_aliases()
def export_to_wav(self, outfile=None): """ cat: save desc: save recording to wav file args: outfile: filename to save to. do not include '.wav' or any other extention """ section_head("Writing to file") if outfile is None: print(" Enter output file name: ", end="") outfile = inpt("file") try: info_line("writing...") t1 = time.time() self.write_audio(outfile) t2 = time.time() info_line("written successfully in {0:.4f} seconds".format(t2 - t1)) except TypeError as e: print(" > Failed to write to file '{0}': {1}".format(outfile, e))
def _do_public_process(method, name=None): """ add reldata, convert docstring """ if name is None: name = method.__name__ add_reldata(method, "public", True) add_reldata(method, "name", name) add_reldata(method, "desc", "") doc = method.__doc__ if doc is not None: doc = [ j for j in [re.sub(r"\s+", " ", i.strip()) for i in doc.split('\n')] if j not in ("", " ") ] args_now = False for line in doc: try: title, content = line.split(":")[0].lower(), line.split(":")[1] if title == "dev": break if not args_now: if title in ("desc", "descrip", "description"): add_reldata(method, "desc", content.strip()) elif title in ("catg", "cat", "category", "catgry", "categry"): cat = Category.get(content.strip()) add_reldata(method, "category", cat) elif title in ("args", "arguments", "arg"): args_now = True else: add_reldata_arg(method, line) except Exception as e: err_mess("Error reading docstring method object data from method '" + method.__name__ + "'", trailing_newline=False) info_line("Docline: '" + str(line) + "'", indent=8) info_line("Exception: " + str(e), indent=8) return method
def options(self): """ cat: info desc: list all process options that can be run on this object (shortcut 'o') """ nl() with style("cyan"): info_block("{CATEGORY}", indent=2) info_line("- {Process}") info_line("{arguments in order, optional if in [square brackets]}", indent=8) nl() meths = {} for mth in self.get_all_public_methods(): cat = get_reldata(mth, "category") try: meths[cat].append(mth) except KeyError: meths[cat] = [mth] categories = list(meths.keys()) # sort by category.value, which is the string representation of that category categories.sort(key=lambda x: x.value) for cat in categories: with style("cyan"): info_line(cat.value.upper(), indent=2) for method in meths[cat]: method._rel_data.display() if cat == Category.PROPERTY: prop_names = self.get_all_prop_names() if not prop_names: info_line("(no properties to edit)", indent=10) else: for i in prop_names: info_line("* " + i, indent=10)
def add_beats(self): """ dev: create beats through prompts or pass 'beat' param to set (??) """ info_block("Creating new Rhythm '{0}'".format(self.name)) while True: info_block( "Enter a beat as <place in rhythm> <optional: length> ('q' to finish, 'i' for more info)", indent=2, hang=2, trailing_newline=False) print(" : ", end="") try: new_beat = inpt("split", "beat", help_callback=self.rhythms_help) except Cancel: info_block("Finished creating Rhythm '{0}'".format(self.name)) return if not (1 <= len(new_beat) <= 2): err_mess( "Wrong number of arguments! From 1 to 2 are required, {0} were supplied" .format(len(new_beat))) continue if secs(new_beat[0]) >= secs(str(self.length) + 'b'): err_mess( "This beat begins after the end of the rhythm! Try again") continue self.beats.append(new_beat) while len(new_beat) < 3: new_beat.append(0) if new_beat[1] == 0: new_beat[1] = "all" info_line(" Added beat - " + self.beat_repr(new_beat))
def display_args(self): for i in self.args: info_line("• " + i.get_display(), indent=8)