Пример #1
0
 def process_project(self):
     if self.current_open_proj is None:
         err_mess("No project is currently open! Open or create one")
     else:
         process(self.current_open_proj)
         self.current_open_proj.save()
         self.current_open_proj = None
Пример #2
0
    def view_waveform(self, start=0, end=None, precision=50):
        """
        cat: info
        desc: show the waveform of this audio
        args:
            [start: seconds/beats to begin view window. default beginning]
            [end: seconds/beats to end view window. -1 selects end. default end]
            [precision: percent of how detailed the plot should be. default 50]
        """
        start = inpt_validate(start, 'beatsec')
        if (end is None) or (end == "-1"):
            end = self.size_samps()
        else:
            end = inpt_validate(end, 'beatsec')
            if end.samples_value >= self.size_samps():
                end = self.size_samps()
        if end <= start:
            err_mess("End cannot be before or equal to start")
            return
        precision = inpt_validate(precision, 'pcnt', allowed=[5, 10000])

        info_block("Generating waveform at {0}%...".format(precision))

        anlsys = Analysis(self, start=start, end=end)
        frame_len = (end - start) / (precision * 2)
        anlsys.set_frame_lengths(frame_len)

        left = anlsys.arr[:, 0]
        right = anlsys.arr[:, 1]

        anlsys.plot(left, right, fill=True)
Пример #3
0
    def playback(self, duration=5, start=0, first_time=True):
        """
        cat: info
        desc: playback this recording's audio
        args:
            [duration: beats/seconds. default 5]
            [start: beat/seconds to start at. defualts to beginning]
        """
        duration = inpt_validate(duration, 'beatsec')
        start = inpt_validate(start, 'beatsec')
        section_head("Playback of '{0}'".format(self.name))

        print("  preparing...")
        start_ind = ind(start)
        if duration <= 0:
            end_ind = self.size_samps()
        else:
            end_ind = start_ind + ind(duration * self.rate)
        arr = self.arr[start_ind : end_ind]
        arr = self.get_panned_rec(arr)

        print("  playing...")
        rate = self.rate.to_rate().round().magnitude
        try:
            sd.play(arr, rate)
            sd.wait()
        except TypeError as e:
            if first_time:
                retry = True
                err_mess("Error playing back. Trying again")
                self.arr = [[float(i), float(j)] for i,j in self.arr]
                self.playback(duration, start, False)
            else:
                raise e
        print("  finished playback")
Пример #4
0
 def process_child(self, child_name=None):
     """
     cat: edit
     desc: edit a child member of this object
     args:
         [child_name: name of child to edit, omit to list children]
     """
     if len(self.children) == 0:
         err_mess("This Project has no children to process!")
     if child_name is None:
         self.list_children()
         p("Enter the name of the child you wish to edit")
         child_name = inpt("name")
     else:
         child_name = inpt_validate(child_name, "name")
     try:
         child_name = autofill(child_name, [i.name for i in self.children])
     except AutofillError as e:
         err_mess("Child name '{0}' not found".format(e.word))
         self.process_child()
         return
     child = None
     for i in self.children:
         if i.name == child_name:
             if child is not None:
                 raise UnexpectedIssue("Multiple children with name {0}".format(child_name))
             child = i
     process(child)
     child.save()
Пример #5
0
    def set_length_and_period(self, length=None, period=None):
        """
        cat: edit
        desc: set the length and period of this rhythm. Give 0 for either argument to keep the current value
        args:
            length: length of the rhythm in beats
            period: standard subdivision of this rhythm, in beats
        """
        if length == 0 and self.length is not None:
            pass
        elif length is None:
            p("Enter a length in beats for this Rhythm")
            length = inpt('beats')
            if length != 0:
                self.length = length
            elif self.length is None:
                err_mess(
                    "There is no current value for length, enter a valid value in beats"
                )
                return self.set_length_and_period(None, period)
        else:
            self.length = inpt_validate(length, 'beats')

        if period == 0 and self.period is not None:
            pass
        elif period is None:
            p("Enter the period, or smallest beat that this Rhythm usually lands on",
              h=True)
            self.period = inpt('beat')
        else:
            self.period = inpt_validate(period, "beat")
Пример #6
0
def process_validate(command, obj):
    """
    check command as valid or one of the shortcuts
    return True on valid
    """
    if command == []:
        err_mess("No command entered")
        command = "None"
    elif command == ['']:
        err_mess(
            "Only alphanumeric characters, spaces, and underscores are allowed"
        )
    elif command[0] in ("q", "quit"):
        p("Save before exiting?")
        if inpt("yn"):
            obj.save()
        info_block("Exiting processing of {0} '{1}'...".format(
            obj.reltype, obj.name))
        raise Cancel(obj)
    elif command[0] in ("o", "options"):
        obj.options()
    elif command[0] in ("h", "help"):
        pass  # callback handled during inpt()
    else:
        return True
    return False
Пример #7
0
 def __init__(self,
              rel_id,
              reltype,
              name,
              path,
              parent,
              custom_path=False,
              **kwargs):
     super().__init__(**kwargs)
     self.parent = parent
     self.reltype = reltype
     self.name = name
     if path is None and not custom_path:
         if self.parent is not None:
             self.path = self.parent.get_data_dir()
         else:
             if Settings.is_debug():
                 err_mess(
                     "Warning: Setting relative path for {0} '{1}'".format(
                         self.reltype, self.name))
                 self.path = "./"
             else:
                 raise UnexpectedIssue("Path is None, with no parent")
         os.makedirs(self.get_data_dir(), exist_ok=True)
     else:
         self.path = path  # path not including object's own directory
     self.rel_id = rel_id if rel_id is not None else RelGlobals.get_next_id(
     )
     if path is not None and reltype != "Program":
         os.makedirs(self.get_data_dir(), exist_ok=True)
Пример #8
0
 def validate_change_type(self, change_type):
     if change_type is None:
         return self.change_type_options[0]
     while change_type not in self.valid_change_types:
         err_mess("Invalid change type '{0}'".format(change_type))
         p("Select one of: {0}".format(", ".join(self.valid_change_types)))
         change_type = inpt('alphanum')
     return change_type
Пример #9
0
def handle_bad_args(e, method_name, args, obj):
    message = str(e)

    if isinstance(e, TypeError) and 'positional argument' in message:
        command = complete_args(e, method_name, args, obj)
        do_command(command, obj)
    elif isinstance(e, ValueError):
        err_mess("Argument entered incorrectly: {0}".format(message))
    else:
        show_error(e)
Пример #10
0
 def undo(self):
     """
     cat: save
     desc: reverts to previous state (maximum of 5 times)
     """
     section_head("Undoing...")
     if len(self.recents) != 0:
         self.arr = self.recents.pop(0)
     else:
         err_mess("No history to revert to!")
Пример #11
0
    def rename(self, name=None):
        """
        cat: meta
        dev: call this method via super, and implement renaming of files other than 
        datafile and its self.path directory
        """
        old_name = self.name
        if old_name is not None:
            old_data_dir = self.get_data_dir()
            old_datafile_name = self.get_data_filename()

        if name is None:
            p("Give this {0} a name".format(self.reltype))
            name = inpt("obj")
        else:
            name = inpt_validate(name, 'obj')

        # validate
        if hasattr(self.parent, "validate_child_name"):
            if self.parent.validate_child_name(self, name):
                self.name = name
                info_block("Named '{0}'".format(name))
            else:
                err_mess("Invalid name")
                self.rename()
        else:
            if Settings.is_debug():
                show_error(
                    AttributeError(
                        "Parent obj '{0}' does not have validate_child_name".
                        format(self.parent)))
            else:
                try:
                    log_err(
                        "Parent object type {0} has no 'validate_child_name' method"
                        .format(self.parent.reltype))
                except AttributeError:
                    log_err(
                        "Parent object '{0}' of '{1}' has no 'validate_child_name' method"
                        .format(self.parent, self))
            self.name = name
            info_block("Named '{0}'".format(name))

        # if actual renaming and not an initial naming
        if old_name is not None:
            new_data_dir = self.get_data_dir()
            # rename dir
            os.rename(old_data_dir, new_data_dir)

            # rename datafile (which is in newdatadir now)
            old_datafile = join_path(new_data_dir,
                                     old_datafile_name,
                                     ext=self.datafile_extension)
            new_datafile = self.get_datafile_fullpath()
            os.rename(old_datafile, new_datafile)
Пример #12
0
 def add_sample(self, new_sample):
     if isinstance(new_sample, Recording):
         if not self.validate_child_name(new_sample, new_sample.name):
             err_mess(
                 "Sample with name '{0}' already exists in Sample Group '{1}'! You may rename it and add it again"
                 .format(new_sample.name, self.name))
     else:
         new_sample = Recording(mode="create",
                                parent=self,
                                reltype="Sample")
     self.samples[new_sample.name] = new_sample
Пример #13
0
 def plot(self):
     """
     cat: info
     desc: plot this controller over time
     """
     if not self.markers:
         err_mess("No data to plot!")
         return
     inds, vals = self.generate()
     channel = np.asarray(list(zip(inds, vals)))
     rel_plot(left_or_mono=channel, start=0, end=max(inds), rate=self.rate)
Пример #14
0
def handle_not_found(e, command, obj):
    process = command[0] if isinstance(command, list) else command
    message = str(e)

    if isinstance(e, (TypeError, KeyError, AutofillError, NoSuchProcess)):
        if isinstance(e, TypeError) and 'not callable' not in message:
            show_error(e)
        if isinstance(e, AutofillError):
            process = e.word
        err_mess("Process '{0}' does not exist: {1}".format(process, message))
    else:
        show_error(e)
Пример #15
0
 def random_method(self):
     """
     desc: implement random sound-editing on recording, with random args. Introduce a little anarchy!
     cat: edit
     """
     public_methods = self.get_all_public_methods()
     public_edits = [i for i in public_methods if get_reldata(i, "category") == Category.EDIT]
     method = rd.choice(public_edits)
     args = method.get_random_defaults()
     try:
         method(*args)
     except Exception as e:
         err_mess("Random Process error:")
         show_error(e)
Пример #16
0
 def plot(self, left, right=None, plot_type="line", fill=None, title=None):
     if left.shape[0] == 0:
         err_mess("No data to plot!")
     else:
         rel_plot(
             left, 
             start=self.start, 
             end=self.end, 
             rate=self.rate,
             right=right,
             fill=fill,
             plot_type=plot_type,
             title=title,
             obj_name=self.obj.name,
             obj_type=self.obj.reltype
         )
Пример #17
0
 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))
Пример #18
0
    def create_proj(self):
        """
        desc: create a new project
        """
        section_head("Creating New Project")
        while True:
            try:
                self.current_open_proj = Project(parent=self, mode="create")
                break
            except FileExistsError:
                err_mess(
                    "The directory already exists and cannot be overwritten. Choose another name or location"
                )

        self.projects[self.current_open_proj.
                      name] = self.current_open_proj.get_data_dir()
        self.write_proj_file()
Пример #19
0
 def process_child_sample(self, name=None):
     """
     desc: process a sample contained in this group
     """
     while True:
         if name is None:
             self.list_samples()
             p("Enter the name of the Sample to process")
             name = inpt('name')
         else:
             name = inpt_validate(name, 'name')
         try:
             self.samples[name]
             break
         except KeyError:
             err_mess("> Sample '{0}' does not exist!".format(name))
     process(self.samples[name])
Пример #20
0
    def __init__(self, parent, doc_line):
        self.optional = False
        if doc_line[0] == "[":
            doc_line = doc_line.strip("[").strip("]")
            self.optional = True

        name,rest = doc_line.split(":", maxsplit=1)
        self.desc = rest.split(';')[0].strip()
        self.name = name.strip()

        self.defaults = [None, None]
        defaults = rest.split(";")
        if len(defaults) > 1:
            defaults = defaults[1].split(',')
            try:
                self.defaults[0] = float(defaults[0])
                self.defaults[1] = float(defaults[1])
            except:
                err_mess("Badly formed defaults on '{0}': {1}".format(parent, defaults))
Пример #21
0
 def property(self, prop_name):
     """
     cat: property
     desc: edit a property
     args:
         property name: one of the following:
     dev: the possible args are generated in options on display
     """
     all_prop_names = self.get_all_prop_names()
     if not all_prop_names:
         err_mess("This {0} has no properties to edit".format(self.reltype))
     try:
         prop_name = autofill(prop_name, all_prop_names)
     except AutofillError as e:
         err_mess("This {0} has property named '{1}'".format(
             self.reltype, e.word))
     else:
         # RelProp.process() method
         getattr(self, prop_name).process()
Пример #22
0
 def process():
     section_head("Editing User Settings")
     method_strs = [func for func in dir(Settings) if "__" not in func and 
         is_public_process(getattr(Settings, func))]
     while True:
         info_title("Available processes:")
         info_list(method_strs)
         p("What process to run?")
         proc = inpt("alphanum")
         try:
             proc = autofill(proc, method_strs)
             method = getattr(Settings, proc)
             if is_public_process(method):
                 method()
             else:
                 raise AttributeError
         except AutofillError as e:
             err_mess("No process matches '{0}'!".format(e.word))
         except AttributeError:
             err_mess("No process matches '{0}'!".format(proc))
Пример #23
0
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
Пример #24
0
    def open_proj(self):
        """
        desc: open a project
        """
        section_head("Opening Project")

        self.list_projects()
        p("Enter name of project you want to open, or 'see <name>' to see info about that project"
          )
        name_input = inpt("split", "obj")
        see = False
        if name_input[0] == "see":
            try:
                proj_name = name_input[1]
            except IndexError:
                err_mess("No name provided to 'see'")
                self.open_proj()
                return
            see = True
        else:
            proj_name = name_input[0]

        try:
            proj_path = self.projects[proj_name]
        except KeyError:
            try:
                proj_name = autofill(proj_name, self.projects.keys(), "name")
            except AutofillError as e:
                err_mess("No project matches name '{0}'".format(e.word))
                return
            proj_path = self.projects[proj_name]

        if proj_path == "None":
            err_mess("Project {0} is missing".format(proj_name))
            self.handle_missing_proj(proj_name)
            return

        if see:
            self.see_proj(proj_name, proj_path)
            self.open_proj()
            return

        try:
            loader = ProjectLoader("{0}.Project".format(proj_name), proj_path,
                                   self)
            self.current_open_proj = loader.get_proj()
        except FileNotFoundError as e:
            err_mess("File Not Found: '{0}'".format(e.filename))
            self.handle_missing_proj(proj_name)
            return
Пример #25
0
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]
Пример #26
0
    def validate_child_name(self, child, new_name):
        if new_name in self.projects:
            err_mess("Project named '{0}' already exists!".format(new_name))
            return False
        if new_name == "see":
            err_mess("'see' is a protected keyword. Choose another name")
            return False

        # if no path, we have to wait until after path is selected to check.
        # this is verified in create_proj()
        if child.path is not None:
            newpath = join_path(child.path,
                                child.get_data_filename(new_name),
                                is_dir=True)
            if os.path.exists(newpath):
                err_mess(
                    "Something already exists at path '{0}'".format(newpath))
                return False

            # update projects file
            try:
                del self.projects[child.name]
            except KeyError:
                pass
            self.projects[new_name] = child.get_data_dir()
            self.write_proj_file()

        return True
Пример #27
0
def complete_args(e, method_name, args, obj):
    """
    handle wrong number of args
    """
    if method_name not in str(e):
        show_error(e)
    err_mess("Wrong number of arguments: {0}".format(str(e)))
    info_title("Arguments for {0}: ".format(method_name), indent=4)
    obj.get_process(method_name)._rel_data.display_args()
    # too many
    command_str = "\n      " + method_name + " "
    if "were given" in str(e):
        p("Enter intended arguments", start=command_str)
        new_args = inpt('split', 'arg')
        return [method_name] + new_args
    # not enough
    else:
        if len(args) > 0:
            command_str += " ".join(args) + " "
        p("Complete arguments", start=command_str)
        new_args = inpt('split', 'arg')
        return [method_name] + args + new_args
Пример #28
0
    def __init__(self, rec, start=0, end=None):
        """
        analysis of rec, with start and end as samps
        """
        self.obj = rec
        self.rate = rec.rate.to_rate().magnitude

        self.start = start
        self.end = end
        if end is None:
            self.end = self.obj.size_samps().magnitude
        if self.end <= self.start:
            err_mess("End cannot be before or equal to start")
            return

        self.arr = rec.arr[self.start:self.end]
        self.mono_arr = np.mean(self.arr, axis=1)
        self.samp_len = self.end - self.start
        self.sec_len = self.samp_len / self.rate
        self.average_amplitude = np.mean(np.abs(self.mono_arr))

        self.frame_length = None
        self.frame_step = None
Пример #29
0
 def move(self, current, new):
     """
     cat: edit
     desc: move a marker to a new location
     Args:
         current: the beat or sec of the marker to move
         new: the beat or sec to move it to
     """
     old_beatsec = inpt_validate(current,
                                 self.time_units,
                                 allowed=self.time_allowed)
     new_beatsec = inpt_validate(new,
                                 self.time_units,
                                 allowed=self.time_allowed)
     old_sample_ind = old_beatsec.to_samps()
     new_samp_ind = new_beatsec.to_samps()
     try:
         marker = self.markers[old_sample_ind]
     except KeyError:
         err_mess("No marker to move at {0}!".format(old_beatsec))
         return
     marker.beatsec = new_beatsec
     self.add_marker(new_samp_ind, marker)
     del self.markers[old_sample_ind]
Пример #30
0
    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))